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-definition-factory.h>
22 #include <dali/devel-api/common/map-wrapper.h>
26 #include <dali-scene3d/internal/loader/hash.h>
27 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
28 #include <dali-scene3d/public-api/loader/node-definition.h>
30 namespace Dali::Scene3D::Loader
34 struct ResourceReceiver : IResourceReceiver
36 const ResourceBundle& mResources;
37 const MeshDefinition* mMeshDef = nullptr;
38 const MaterialDefinition* mMaterialDef = nullptr;
40 ResourceReceiver(const ResourceBundle& resources)
41 : mResources(resources)
45 void Register(ResourceType::Value type, Index id) override
49 case ResourceType::Mesh:
50 mMeshDef = &mResources.mMeshes[id].first;
53 case ResourceType::Material:
54 mMaterialDef = &mResources.mMaterials[id].first;
63 uint64_t HashNode(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
67 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
68 hash.Add(hasTransparency);
71 materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
72 materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
73 materialDef.CheckTextures(MaterialDefinition::NORMAL))
77 // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
78 if(materialDef.CheckTextures(MaterialDefinition::ALBEDO))
83 if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
88 if(materialDef.CheckTextures(MaterialDefinition::NORMAL))
94 if(materialDef.GetAlphaCutoff() > 0.f)
96 hash.Add("ALPH" /*A_TEST*/);
99 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
104 if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
106 hash.Add("OCCL" /*USION*/);
109 if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
111 hash.Add("EMIS" /*SIVE*/);
114 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
119 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
121 hash.Add("SPECCOLTEX");
124 if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
126 hash.Add("GLTF" /*_CHANNELS*/);
129 if(meshDef.IsSkinned())
131 hash.Add("SKIN" /*NING*/);
134 if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
136 hash.Add("FLIP" /*_V*/);
139 if(meshDef.mColors.IsDefined())
144 if(meshDef.mTangentType == Property::VECTOR4)
149 if(meshDef.HasBlendShapes())
151 bool hasPositions = false;
152 bool hasNormals = false;
153 bool hasTangents = false;
154 meshDef.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
157 hash.Add("MORPHPOS");
162 hash.Add("MORPHNOR");
167 hash.Add("MORPHTAN");
170 if(hasPositions || hasNormals || hasTangents)
174 if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
185 struct ShaderDefinitionFactory::Impl
187 ResourceBundle* mResources; // no ownership
188 std::map<uint64_t, Index> mShaderMap;
191 ShaderDefinitionFactory::ShaderDefinitionFactory()
196 ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
198 void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
200 mImpl->mResources = &resources;
201 mImpl->mShaderMap.clear();
204 Index ShaderDefinitionFactory::ProduceShader(NodeDefinition::Renderable& renderable)
206 auto& resources = *mImpl->mResources;
208 ResourceReceiver receiver{resources};
209 renderable.RegisterResources(receiver);
211 if(!(receiver.mMeshDef && receiver.mMaterialDef))
213 renderable.mShaderIdx = INVALID_INDEX;
214 return INVALID_INDEX;
217 auto& shaderMap = mImpl->mShaderMap;
218 uint64_t hash = HashNode(*receiver.mMaterialDef, *receiver.mMeshDef);
219 auto iFind = shaderMap.find(hash);
220 if(iFind != shaderMap.end())
222 renderable.mShaderIdx = iFind->second;
226 ShaderDefinition shaderDef;
227 shaderDef.mUseBuiltInShader = true;
228 shaderDef.mRendererState = RendererState::DEPTH_TEST;
230 auto& materialDef = *receiver.mMaterialDef;
231 if(!materialDef.mDoubleSided)
233 shaderDef.mRendererState |= RendererState::CULL_BACK;
236 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
239 // TODO: this requires more granularity
240 shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND);
243 if(hasTransparency ||
244 !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
245 !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
248 shaderDef.mDefines.push_back("THREE_TEX");
250 // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
251 if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
253 shaderDef.mDefines.push_back("BASECOLOR_TEX");
256 if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
258 shaderDef.mDefines.push_back("METALLIC_ROUGHNESS_TEX");
261 if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
263 shaderDef.mDefines.push_back("NORMAL_TEX");
267 if(materialDef.GetAlphaCutoff() > 0.f)
269 shaderDef.mDefines.push_back("ALPHA_TEST");
272 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
274 shaderDef.mDefines.push_back("SSS");
277 if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
279 shaderDef.mDefines.push_back("OCCLUSION");
282 if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
284 shaderDef.mDefines.push_back("EMISSIVE_TEXTURE");
287 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
289 shaderDef.mDefines.push_back("MATERIAL_SPECULAR_TEXTURE");
292 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
294 shaderDef.mDefines.push_back("MATERIAL_SPECULAR_COLOR_TEXTURE");
297 if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
299 shaderDef.mDefines.push_back("GLTF_CHANNELS");
302 const auto& meshDef = *receiver.mMeshDef;
303 if(meshDef.IsSkinned())
305 shaderDef.mDefines.push_back("SKINNING");
308 if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
310 shaderDef.mDefines.push_back("FLIP_V");
313 if(meshDef.mColors.IsDefined())
315 shaderDef.mDefines.push_back("COLOR_ATTRIBUTE");
318 if(meshDef.mTangentType == Property::VECTOR4)
320 shaderDef.mDefines.push_back("VEC4_TANGENT");
323 if(meshDef.HasBlendShapes())
325 bool hasPositions = false;
326 bool hasNormals = false;
327 bool hasTangents = false;
328 meshDef.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
332 shaderDef.mDefines.push_back("MORPH_POSITION");
337 shaderDef.mDefines.push_back("MORPH_NORMAL");
342 shaderDef.mDefines.push_back("MORPH_TANGENT");
345 if(hasPositions || hasNormals || hasTangents)
347 shaderDef.mDefines.push_back("MORPH");
349 if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
351 shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
356 shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
358 Index result = resources.mShaders.size();
359 shaderMap[hash] = result;
361 resources.mShaders.emplace_back(std::move(shaderDef), Shader());
363 renderable.mShaderIdx = result;
366 return renderable.mShaderIdx;
369 } // namespace Dali::Scene3D::Loader