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/internal/model-components/model-primitive-impl.h>
22 #include <dali/devel-api/adaptor-framework/image-loading.h>
23 #include <dali/public-api/animation/constraint.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/public-api/object/type-registry.h>
28 #include <dali-scene3d/internal/common/image-resource-loader.h>
29 #include <dali-scene3d/internal/light/light-impl.h>
30 #include <dali-scene3d/internal/model-components/material-impl.h>
31 #include <dali-scene3d/public-api/loader/environment-definition.h>
33 #include <dali/integration-api/debug.h>
34 #include <dali/public-api/object/property-array.h>
35 #include <dali/public-api/object/property-map.h>
38 namespace fs = std::filesystem;
48 #if defined(DEBUG_ENABLED)
49 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_SCENE3D_MODEL_PRIMITIVE");
51 #define DALI_LOG_WRITE_FILE(filename, stream) \
53 fs::path tmp = fs::temp_directory_path(); \
55 std::ofstream ostrm(tmp, std::ios::out); \
60 inline Property::Map GetMap(Shader shader)
62 Property::Value program = shader[Shader::Property::PROGRAM];
63 Property::Map* map{nullptr};
64 if(program.GetType() == Property::ARRAY)
66 Property::Array* array = program.GetArray();
69 Property::Value& value = array->GetElementAt(0);
70 if(value.GetType() == Property::MAP)
76 else if(program.GetType() == Property::MAP)
78 map = program.GetMap();
84 return Property::Map();
89 * Creates control through type registry
93 return Scene3D::ModelPrimitive::New();
96 // Setup properties, signals and actions using the type-registry.
97 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelPrimitive, Dali::BaseHandle, Create);
98 DALI_TYPE_REGISTRATION_END()
100 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
102 } // unnamed namespace
104 ModelPrimitivePtr ModelPrimitive::New()
106 ModelPrimitivePtr primitive = new ModelPrimitive();
108 primitive->Initialize();
113 ModelPrimitive::ModelPrimitive()
114 : mShaderManager(new Scene3D::Loader::ShaderManager())
118 ModelPrimitive::~ModelPrimitive()
122 GetImplementation(mMaterial).RemoveObserver(this);
127 void ModelPrimitive::Initialize()
131 void ModelPrimitive::SetRenderer(Dali::Renderer renderer)
133 mRenderer = renderer;
134 mGeometry = renderer.GetGeometry();
135 mTextureSet = renderer.GetTextures();
136 mShader = renderer.GetShader();
139 Dali::Renderer ModelPrimitive::GetRenderer() const
144 void ModelPrimitive::SetGeometry(Dali::Geometry geometry)
146 mGeometry = geometry;
150 Dali::Geometry ModelPrimitive::GetGeometry() const
155 void ModelPrimitive::SetMaterial(Dali::Scene3D::Material material, bool updateRenderer)
162 if(mMaterial != material)
164 // Stop observe from previous material.
167 GetImplementation(mMaterial).RemoveObserver(this);
170 mMaterial = material;
172 // Start observe from new material.
176 GetImplementation(mMaterial).AddObserver(this);
181 mIsMaterialChanged = true;
182 if(GetImplementation(mMaterial).IsResourceReady())
184 GetImplementation(mMaterial).UpdateMaterialData();
185 ApplyMaterialToRenderer();
188 UpdateShadowMapTexture();
189 UpdateImageBasedLightTexture();
193 Dali::Scene3D::Material ModelPrimitive::GetMaterial() const
198 void ModelPrimitive::AddPrimitiveObserver(ModelPrimitiveModifyObserver* observer)
200 mObservers.insert(observer);
203 void ModelPrimitive::RemovePrimitiveObserver(ModelPrimitiveModifyObserver* observer)
205 mObservers.erase(observer);
208 void ModelPrimitive::SetShadowMapTexture(Dali::Texture shadowMapTexture)
210 mShadowMapTexture = shadowMapTexture;
211 UpdateShadowMapTexture();
214 void ModelPrimitive::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
216 mDiffuseTexture = diffuseTexture;
217 mSpecularTexture = specularTexture;
218 mIblScaleFactor = iblScaleFactor;
219 mSpecularMipmapLevels = specularMipmapLevels;
221 UpdateImageBasedLightTexture();
224 void ModelPrimitive::SetImageBasedLightScaleFactor(float iblScaleFactor)
226 mIblScaleFactor = iblScaleFactor;
227 if(mRenderer && mMaterial)
229 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), iblScaleFactor);
233 void ModelPrimitive::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
235 if(mShaderManager != shaderManager)
237 mShaderManager = (shaderManager) ? shaderManager : new Scene3D::Loader::ShaderManager();
238 if(mMaterial && GetImplementation(mMaterial).IsResourceReady())
240 ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag::SHADER);
245 void ModelPrimitive::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data)
247 mBlendShapeData = std::move(data);
248 Scene3D::Loader::BlendShapes::ConfigureProperties(mBlendShapeData, mRenderer);
251 void ModelPrimitive::SetBlendShapeGeometry(Dali::Texture blendShapeGeometry)
253 mBlendShapeGeometry = blendShapeGeometry;
256 void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents, Scene3D::Loader::BlendShapes::Version version)
258 mHasPositions = hasPositions;
259 mHasNormals = hasNormals;
260 mHasTangents = hasTangents;
261 mBlendShapeVersion = version;
264 void ModelPrimitive::SetSkinned(bool isSkinned, uint32_t numberOfJointSets)
266 mHasSkinning = isSkinned;
267 mNumberOfJointSets = numberOfJointSets;
270 // From MaterialModifyObserver
272 void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, MaterialModifyObserver::ModifyFlag flag)
274 ApplyMaterialToRenderer(flag);
277 void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
284 uint32_t shaderFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER));
285 if(mIsMaterialChanged || shaderFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER))
287 Scene3D::Loader::ShaderOption shaderOption = GetImplementation(mMaterial).GetShaderOption();
289 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::VEC4_TANGENT);
292 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::SKINNING);
293 shaderOption.AddJointMacros(mNumberOfJointSets);
295 if(mHasPositions || mHasNormals || mHasTangents)
299 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_POSITION);
303 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_NORMAL);
307 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_TANGENT);
309 if(mBlendShapeVersion == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
311 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_VERSION_2_0);
315 Shader newShader = mShaderManager->ProduceShader(shaderOption);
316 if(mShader != newShader)
318 DALI_LOG_INFO(gLogFilter, Debug::General, "Warning! Model primitive shader changed\n");
319 #if defined(DEBUG_ENABLED)
322 Property::Map oldMap = GetMap(mShader);
323 DALI_LOG_WRITE_FILE("oldShader.txt", "Vertex Shader:\n"
324 << oldMap["vertex"] << "\n\nFragmentShader: " << oldMap["fragment"] << "\n");
328 Property::Map newMap = GetMap(newShader);
329 DALI_LOG_WRITE_FILE("newShader.txt", "Vertex Shader:\n"
330 << newMap["vertex"] << "\n\nFragmentShader: " << newMap["fragment"] << "\n");
342 mRenderer.SetShader(mShader);
346 uint32_t textureFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE));
347 if(mIsMaterialChanged || textureFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE))
349 mTextureSet = GetImplementation(mMaterial).GetTextureSet();
351 if(mBlendShapeGeometry)
353 TextureSet newTextureSet = TextureSet::New();
354 newTextureSet.SetTexture(0u, mBlendShapeGeometry);
356 const unsigned int numberOfTextures = mTextureSet.GetTextureCount();
357 for(unsigned int index = 0u; index < numberOfTextures; ++index)
359 const unsigned int newIndex = index + 1u;
360 newTextureSet.SetTexture(newIndex, mTextureSet.GetTexture(index));
361 newTextureSet.SetSampler(newIndex, mTextureSet.GetSampler(index));
364 mTextureSet = newTextureSet;
367 uint32_t textureCount = mTextureSet.GetTextureCount();
369 if(!mShadowMapTexture)
371 mShadowMapTexture = Dali::Scene3D::Internal::ImageResourceLoader::GetEmptyTextureWhiteRGB();
373 mTextureSet.SetTexture(textureCount++, mShadowMapTexture);
375 Texture brdfTexture = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
376 if(!mSpecularTexture || !mDiffuseTexture)
378 Scene3D::Loader::EnvironmentMapData environmentMapData;
379 environmentMapData.mPixelData.resize(6);
380 for(auto& face : environmentMapData.mPixelData)
382 face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
384 environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP);
385 Texture iblTexture = environmentMapData.GetTexture();
386 mDiffuseTexture = iblTexture;
387 mSpecularTexture = iblTexture;
390 mTextureSet.SetTexture(textureCount++, brdfTexture);
391 mTextureSet.SetTexture(textureCount++, mDiffuseTexture);
392 mTextureSet.SetTexture(textureCount, mSpecularTexture);
394 auto specularSampler = Sampler::New();
395 specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
396 specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
397 mTextureSet.SetSampler(textureCount, specularSampler);
405 mRenderer.SetTextures(mTextureSet);
409 uint32_t uniformFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM));
410 if(mIsMaterialChanged || uniformFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM))
414 mNeedToSetRendererUniform = true;
418 UpdateRendererUniform();
421 mIsMaterialChanged = false;
424 void ModelPrimitive::CreateRenderer()
426 if(!mShader || !mGeometry || !mTextureSet || mRenderer)
431 mRenderer = Renderer::New(mGeometry, mShader);
432 mRenderer.SetTextures(mTextureSet);
433 UpdateRendererUniform();
435 for(auto* observer : mObservers)
437 observer->OnRendererCreated(mRenderer);
441 void ModelPrimitive::UpdateShadowMapTexture()
443 if(mRenderer && mMaterial)
445 Dali::TextureSet textures = mRenderer.GetTextures();
451 uint32_t textureCount = textures.GetTextureCount();
452 if(mShadowMapTexture &&
453 textureCount >= GetImplementation(mMaterial).GetShadowMapTextureOffset() &&
454 textures.GetTexture(textureCount - GetImplementation(mMaterial).GetShadowMapTextureOffset()) != mShadowMapTexture)
456 Dali::TextureSet newTextures = Dali::TextureSet::New();
458 for(uint32_t index = 0u; index < textureCount; ++index)
460 Dali::Texture texture = textures.GetTexture(index);
461 if(index == textureCount - GetImplementation(mMaterial).GetShadowMapTextureOffset())
463 texture = (!!mShadowMapTexture) ? mShadowMapTexture : Dali::Scene3D::Internal::ImageResourceLoader::GetEmptyTextureWhiteRGB();
466 newTextures.SetTexture(index, texture);
467 newTextures.SetSampler(index, textures.GetSampler(index));
470 mRenderer.SetTextures(newTextures);
475 void ModelPrimitive::UpdateImageBasedLightTexture()
477 if(mRenderer && mMaterial)
479 Dali::TextureSet textures = mRenderer.GetTextures();
485 uint32_t textureCount = textures.GetTextureCount();
486 if(textureCount > 2u &&
487 (textures.GetTexture(textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset()) != mDiffuseTexture ||
488 textures.GetTexture(textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset()) != mSpecularTexture))
490 Dali::TextureSet newTextures = Dali::TextureSet::New();
492 for(uint32_t index = 0u; index < textureCount; ++index)
494 Dali::Texture texture = textures.GetTexture(index);
495 if(index == textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset())
497 texture = mDiffuseTexture;
499 else if(index == textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset())
501 texture = mSpecularTexture;
504 newTextures.SetTexture(index, texture);
505 newTextures.SetSampler(index, textures.GetSampler(index));
508 mRenderer.SetTextures(newTextures);
510 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
511 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
515 void ModelPrimitive::UpdateRendererUniform()
519 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
520 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
521 GetImplementation(mMaterial).SetRendererUniform(mRenderer);
525 } // namespace Internal
527 } // namespace Scene3D