2 * Copyright (c) 2022 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.
17 #include "dali-scene3d/public-api/loader/shader-definition-factory.h"
19 #include "dali-scene3d/internal/loader/hash.h"
20 #include "dali-scene3d/public-api/loader/blend-shape-details.h"
21 #include "dali-scene3d/public-api/loader/node-definition.h"
22 #include "dali/devel-api/common/map-wrapper.h"
32 struct ResourceReceiver : IResourceReceiver
34 const ResourceBundle& mResources;
35 const MeshDefinition* mMeshDef = nullptr;
36 const MaterialDefinition* mMaterialDef = nullptr;
38 ResourceReceiver(const ResourceBundle& resources)
39 : mResources(resources)
43 void Register(ResourceType::Value type, Index id) override
47 case ResourceType::Mesh:
48 mMeshDef = &mResources.mMeshes[id].first;
51 case ResourceType::Material:
52 mMaterialDef = &mResources.mMaterials[id].first;
61 void RetrieveBlendShapeComponents(const std::vector<MeshDefinition::BlendShape>& blendShapes, bool& hasPositions, bool& hasNormals, bool& hasTangents)
63 for(const auto& blendShape : blendShapes)
65 hasPositions = hasPositions || blendShape.deltas.IsDefined();
66 hasNormals = hasNormals || blendShape.normals.IsDefined();
67 hasTangents = hasTangents || blendShape.tangents.IsDefined();
71 uint64_t HashNode(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
75 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
76 hash.Add(hasTransparency);
79 materialDef.CheckTextures(MaterialDefinition::ALBEDO) ||
80 materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS) ||
81 materialDef.CheckTextures(MaterialDefinition::NORMAL))
85 // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
86 if(materialDef.CheckTextures(MaterialDefinition::ALBEDO))
91 if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
96 if(materialDef.CheckTextures(MaterialDefinition::NORMAL))
102 if(materialDef.GetAlphaCutoff() > 0.f)
104 hash.Add("ALPH" /*A_TEST*/);
107 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
112 if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
114 hash.Add("OCCL" /*USION*/);
117 if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
119 hash.Add("EMIS" /*SIVE*/);
122 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
127 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
129 hash.Add("SPECCOLTEX");
132 if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
134 hash.Add("GLTF" /*_CHANNELS*/);
137 if(meshDef.IsSkinned())
139 hash.Add("SKIN" /*NING*/);
142 if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
144 hash.Add("FLIP" /*_V*/);
147 if(meshDef.mColors.IsDefined())
152 if(meshDef.mTangentType == Property::VECTOR4)
157 if(meshDef.HasBlendShapes())
159 bool hasPositions = false;
160 bool hasNormals = false;
161 bool hasTangents = false;
162 RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
165 hash.Add("MORPHPOS");
170 hash.Add("MORPHNOR");
175 hash.Add("MORPHTAN");
178 if(hasPositions || hasNormals || hasTangents)
182 if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
193 struct ShaderDefinitionFactory::Impl
195 ResourceBundle* mResources; // no ownership
196 std::map<uint64_t, Index> mShaderMap;
199 ShaderDefinitionFactory::ShaderDefinitionFactory()
204 ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
206 void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
208 mImpl->mResources = &resources;
209 mImpl->mShaderMap.clear();
212 Index ShaderDefinitionFactory::ProduceShader(NodeDefinition::Renderable& renderable)
214 auto& resources = *mImpl->mResources;
216 ResourceReceiver receiver{resources};
217 renderable.RegisterResources(receiver);
219 if(!(receiver.mMeshDef && receiver.mMaterialDef))
221 renderable.mShaderIdx = INVALID_INDEX;
222 return INVALID_INDEX;
225 auto& shaderMap = mImpl->mShaderMap;
226 uint64_t hash = HashNode(*receiver.mMaterialDef, *receiver.mMeshDef);
227 auto iFind = shaderMap.find(hash);
228 if(iFind != shaderMap.end())
230 renderable.mShaderIdx = iFind->second;
234 ShaderDefinition shaderDef;
235 shaderDef.mUseBuiltInShader = true;
236 shaderDef.mRendererState = RendererState::DEPTH_TEST;
238 auto& materialDef = *receiver.mMaterialDef;
239 if(!materialDef.mDoubleSided)
241 shaderDef.mRendererState |= RendererState::CULL_BACK;
244 const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
247 // TODO: this requires more granularity
248 shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND);
251 if(hasTransparency ||
252 !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
253 !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
256 shaderDef.mDefines.push_back("THREE_TEX");
258 // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
259 if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
261 shaderDef.mDefines.push_back("BASECOLOR_TEX");
264 if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
266 shaderDef.mDefines.push_back("METALLIC_ROUGHNESS_TEX");
269 if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
271 shaderDef.mDefines.push_back("NORMAL_TEX");
275 if(materialDef.GetAlphaCutoff() > 0.f)
277 shaderDef.mDefines.push_back("ALPHA_TEST");
280 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
282 shaderDef.mDefines.push_back("SSS");
285 if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
287 shaderDef.mDefines.push_back("OCCLUSION");
290 if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
292 shaderDef.mDefines.push_back("EMISSIVE");
295 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
297 shaderDef.mDefines.push_back("MATERIAL_SPECULAR_TEXTURE");
300 if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
302 shaderDef.mDefines.push_back("MATERIAL_SPECULAR_COLOR_TEXTURE");
305 if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
307 shaderDef.mDefines.push_back("GLTF_CHANNELS");
310 const auto& meshDef = *receiver.mMeshDef;
311 if(meshDef.IsSkinned())
313 shaderDef.mDefines.push_back("SKINNING");
316 if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
318 shaderDef.mDefines.push_back("FLIP_V");
321 if(meshDef.mColors.IsDefined())
323 shaderDef.mDefines.push_back("COLOR_ATTRIBUTE");
326 if(meshDef.mTangentType == Property::VECTOR4)
328 shaderDef.mDefines.push_back("VEC4_TANGENT");
331 if(meshDef.HasBlendShapes())
333 bool hasPositions = false;
334 bool hasNormals = false;
335 bool hasTangents = false;
336 RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
340 shaderDef.mDefines.push_back("MORPH_POSITION");
345 shaderDef.mDefines.push_back("MORPH_NORMAL");
350 shaderDef.mDefines.push_back("MORPH_TANGENT");
353 if(hasPositions || hasNormals || hasTangents)
355 shaderDef.mDefines.push_back("MORPH");
357 if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
359 shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
364 shaderDef.mUniforms["uMaxLOD"] = 6.f;
365 shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
367 Index result = resources.mShaders.size();
368 shaderMap[hash] = result;
370 resources.mShaders.emplace_back(std::move(shaderDef), Shader());
372 renderable.mShaderIdx = result;
375 return renderable.mShaderIdx;
378 } // namespace Loader
379 } // namespace Scene3D