2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-scene3d/public-api/loader/shader-manager.h>
22 #include <dali/devel-api/common/map-wrapper.h>
23 #include <dali/public-api/animation/constraint.h>
27 #include <dali-scene3d/internal/light/light-impl.h>
28 #include <dali-scene3d/internal/loader/hash.h>
29 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
30 #include <dali-scene3d/public-api/loader/node-definition.h>
32 namespace Dali::Scene3D::Loader
36 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
38 ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
42 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
45 option.SetTransparency();
49 !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
50 !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
52 option.AddOption(ShaderOption::Type::THREE_TEXTURE);
54 // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
55 if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
57 option.AddOption(ShaderOption::Type::BASE_COLOR_TEXTURE);
60 if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
62 option.AddOption(ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE);
65 if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
67 option.AddOption(ShaderOption::Type::NORMAL_TEXTURE);
71 if(materialDef.GetAlphaCutoff() > 0.f)
73 option.AddOption(ShaderOption::Type::ALPHA_TEST);
76 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
78 option.AddOption(ShaderOption::Type::SUBSURFACE);
81 if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
83 option.AddOption(ShaderOption::Type::OCCLUSION);
86 if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
88 option.AddOption(ShaderOption::Type::EMISSIVE);
91 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
93 option.AddOption(ShaderOption::Type::SPECULAR);
96 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
98 option.AddOption(ShaderOption::Type::SPECULAR_COLOR);
101 if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
103 option.AddOption(ShaderOption::Type::GLTF_CHANNELS);
106 if(meshDef.IsSkinned())
108 option.AddOption(ShaderOption::Type::SKINNING);
111 if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
113 option.AddOption(ShaderOption::Type::FLIP_UVS_VERTICAL);
116 if(meshDef.mColors.IsDefined())
118 option.AddOption(ShaderOption::Type::COLOR_ATTRIBUTE);
121 if(meshDef.mTangentType == Property::VECTOR4)
123 option.AddOption(ShaderOption::Type::VEC4_TANGENT);
126 if(meshDef.HasBlendShapes())
128 bool hasPositions = false;
129 bool hasNormals = false;
130 bool hasTangents = false;
131 meshDef.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
134 option.AddOption(ShaderOption::Type::MORPH_POSITION);
139 option.AddOption(ShaderOption::Type::MORPH_NORMAL);
144 option.AddOption(ShaderOption::Type::MORPH_TANGENT);
147 if(hasPositions || hasNormals || hasTangents)
149 if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
151 option.AddOption(ShaderOption::Type::MORPH_VERSION_2_0);
160 struct ShaderManager::Impl
162 std::map<uint64_t, Index> mShaderMap;
163 std::vector<Dali::Shader> mShaders;
164 std::vector<Scene3D::Light> mLights;
167 ShaderManager::ShaderManager()
172 ShaderManager::~ShaderManager() = default;
174 Dali::Shader ShaderManager::ProduceShader(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
176 ShaderOption option = MakeOption(materialDefinition, meshDefinition);
177 return ProduceShader(option);
180 Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
184 auto& shaderMap = mImpl->mShaderMap;
185 uint64_t hash = shaderOption.GetOptionHash();
186 auto iFind = shaderMap.find(hash);
187 if(iFind != shaderMap.end())
189 result = mImpl->mShaders[iFind->second];
193 ShaderDefinition shaderDef;
194 shaderDef.mUseBuiltInShader = true;
196 shaderOption.GetDefines(shaderDef.mDefines);
197 shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
199 shaderMap[hash] = mImpl->mShaders.size();
201 auto raw = shaderDef.LoadRaw("");
202 mImpl->mShaders.emplace_back(shaderDef.Load(std::move(raw)));
203 result = mImpl->mShaders.back();
205 std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
206 result.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
208 for(uint32_t index = 0; index < mImpl->mLights.size(); ++index)
210 SetLightConstraintToShader(index, result);
217 RendererState::Type ShaderManager::GetRendererState(const MaterialDefinition& materialDefinition)
219 RendererState::Type rendererState = RendererState::DEPTH_TEST;
221 if(!materialDefinition.mDoubleSided)
223 rendererState |= RendererState::CULL_BACK;
226 const bool hasTransparency = MaskMatch(materialDefinition.mFlags, MaterialDefinition::TRANSPARENCY);
229 // TODO: this requires more granularity
230 rendererState = (rendererState | RendererState::ALPHA_BLEND);
232 return rendererState;
235 bool ShaderManager::AddLight(Scene3D::Light light)
237 if(!light || mImpl->mLights.size() >= Scene3D::Internal::Light::GetMaximumEnabledLightCount())
242 uint32_t lightIndex = mImpl->mLights.size();
243 mImpl->mLights.push_back(light);
245 for(auto&& shader : mImpl->mShaders)
247 std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
248 shader.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
251 SetLightConstraint(lightIndex);
256 void ShaderManager::RemoveLight(Scene3D::Light light)
258 uint32_t lightCount = mImpl->mLights.size();
259 for(uint32_t index = 0; index < lightCount; ++index)
261 if(mImpl->mLights[index] != light)
266 RemoveLightConstraint(index);
268 if(!mImpl->mLights.empty() && light != mImpl->mLights.back())
270 RemoveLightConstraint(mImpl->mLights.size() - 1);
271 mImpl->mLights[index] = mImpl->mLights.back();
272 SetLightConstraint(index);
275 mImpl->mLights.pop_back();
277 for(auto&& shader : mImpl->mShaders)
279 std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
280 shader.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
286 uint32_t ShaderManager::GetLightCount() const
288 return mImpl->mLights.size();
291 void ShaderManager::SetLightConstraint(uint32_t lightIndex)
293 for(auto&& shader : mImpl->mShaders)
295 SetLightConstraintToShader(lightIndex, shader);
299 void ShaderManager::SetLightConstraintToShader(uint32_t lightIndex, Dali::Shader shader)
301 std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
302 lightDirectionPropertyName += "[" + std::to_string(lightIndex) + "]";
303 auto lightDirectionPropertyIndex = shader.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
304 Dali::Constraint lightDirectionConstraint = Dali::Constraint::New<Vector3>(shader, lightDirectionPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) { output = inputs[0]->GetQuaternion().Rotate(Vector3::ZAXIS); });
305 lightDirectionConstraint.AddSource(Source{mImpl->mLights[lightIndex], Dali::Actor::Property::WORLD_ORIENTATION});
306 lightDirectionConstraint.ApplyPost();
307 lightDirectionConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
309 std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
310 lightColorPropertyName += "[" + std::to_string(lightIndex) + "]";
311 auto lightColorPropertyIndex = shader.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
312 Dali::Constraint lightColorConstraint = Dali::Constraint::New<Vector3>(shader, lightColorPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) { output = Vector3(inputs[0]->GetVector4()); });
313 lightColorConstraint.AddSource(Source{mImpl->mLights[lightIndex], Dali::Actor::Property::COLOR});
314 lightColorConstraint.ApplyPost();
315 lightColorConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
318 void ShaderManager::RemoveLightConstraint(uint32_t lightIndex)
320 for(auto&& shader : mImpl->mShaders)
322 shader.RemoveConstraints(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
326 } // namespace Dali::Scene3D::Loader