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/light/light-impl.h>
29 #include <dali-scene3d/internal/model-components/material-impl.h>
30 #include <dali-scene3d/public-api/loader/environment-definition.h>
41 * Creates control through type registry
45 return Scene3D::ModelPrimitive::New();
48 // Setup properties, signals and actions using the type-registry.
49 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelPrimitive, Dali::BaseHandle, Create);
50 DALI_TYPE_REGISTRATION_END()
52 constexpr std::string_view MORPH_KEYWORD = "MORPH";
53 constexpr std::string_view MORPH_POSITION_KEYWORD = "MORPH_POSITION";
54 constexpr std::string_view MORPH_NORMAL_KEYWORD = "MORPH_NORMAL";
55 constexpr std::string_view MORPH_TANGENT_KEYWORD = "MORPH_TANGENT";
56 constexpr std::string_view MORPH_VERSION_2_0_KEYWORD = "MORPH_VERSION_2_0";
58 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
59 } // unnamed namespace
61 ModelPrimitivePtr ModelPrimitive::New()
63 ModelPrimitivePtr primitive = new ModelPrimitive();
65 primitive->Initialize();
70 ModelPrimitive::ModelPrimitive()
74 ModelPrimitive::~ModelPrimitive()
78 GetImplementation(mMaterial).RemoveObserver(this);
83 void ModelPrimitive::Initialize()
85 mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount());
88 void ModelPrimitive::SetRenderer(Dali::Renderer renderer)
91 mGeometry = renderer.GetGeometry();
92 mTextureSet = renderer.GetTextures();
93 mShader = renderer.GetShader();
96 Dali::Renderer ModelPrimitive::GetRenderer() const
101 void ModelPrimitive::SetGeometry(Dali::Geometry geometry)
103 mGeometry = geometry;
107 Dali::Geometry ModelPrimitive::GetGeometry() const
112 void ModelPrimitive::SetMaterial(Dali::Scene3D::Material material, bool updateRenderer)
119 if(mMaterial != material)
121 // Stop observe from previous material.
124 GetImplementation(mMaterial).RemoveObserver(this);
127 mMaterial = material;
129 // Start observe from new material.
133 GetImplementation(mMaterial).AddObserver(this);
138 mIsMaterialChanged = true;
139 if(GetImplementation(mMaterial).IsResourceReady())
141 GetImplementation(mMaterial).UpdateMaterialData();
142 ApplyMaterialToRenderer();
145 UpdateImageBasedLightTexture();
149 Dali::Scene3D::Material ModelPrimitive::GetMaterial() const
154 void ModelPrimitive::AddPrimitiveObserver(ModelPrimitiveModifyObserver* observer)
156 mObservers.insert(observer);
159 void ModelPrimitive::RemovePrimitiveObserver(ModelPrimitiveModifyObserver* observer)
161 mObservers.erase(observer);
164 void ModelPrimitive::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
166 mDiffuseTexture = diffuseTexture;
167 mSpecularTexture = specularTexture;
168 mIblScaleFactor = iblScaleFactor;
169 mSpecularMipmapLevels = specularMipmapLevels;
171 UpdateImageBasedLightTexture();
174 void ModelPrimitive::SetImageBasedLightScaleFactor(float iblScaleFactor)
176 mIblScaleFactor = iblScaleFactor;
177 if(mRenderer && mMaterial)
179 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), iblScaleFactor);
183 void ModelPrimitive::AddLight(Scene3D::Light light, uint32_t lightIndex)
185 if(mLights[lightIndex])
187 RemoveLight(lightIndex);
190 mLights[lightIndex] = light;
191 // TODO Remove light at lightIndex if it is already set.
192 if(mRenderer && mMaterial)
195 std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
196 mRenderer.RegisterProperty(lightCountPropertyName, mLightCount);
198 std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
199 lightDirectionPropertyName += "[" + std::to_string(lightIndex) + "]";
200 auto lightDirectionPropertyIndex = mRenderer.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
201 Dali::Constraint lightDirectionConstraint = Dali::Constraint::New<Vector3>(mRenderer, lightDirectionPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs)
202 { output = inputs[0]->GetQuaternion().Rotate(Vector3::ZAXIS); });
203 lightDirectionConstraint.AddSource(Source{light, Dali::Actor::Property::WORLD_ORIENTATION});
204 lightDirectionConstraint.ApplyPost();
205 lightDirectionConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
207 std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
208 lightColorPropertyName += "[" + std::to_string(lightIndex) + "]";
209 auto lightColorPropertyIndex = mRenderer.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
210 Dali::Constraint lightColorConstraint = Dali::Constraint::New<Vector3>(mRenderer, lightColorPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs)
211 { output = Vector3(inputs[0]->GetVector4()); });
212 lightColorConstraint.AddSource(Source{light, Dali::Actor::Property::COLOR});
213 lightColorConstraint.ApplyPost();
214 lightColorConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
218 void ModelPrimitive::RemoveLight(uint32_t lightIndex)
221 std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
222 mRenderer.RegisterProperty(lightCountPropertyName, mLightCount);
224 mRenderer.RemoveConstraints(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
226 mLights[lightIndex].Reset();
229 void ModelPrimitive::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data)
231 mBlendShapeData = std::move(data);
232 Scene3D::Loader::BlendShapes::ConfigureProperties(mBlendShapeData, mRenderer);
235 void ModelPrimitive::SetBlendShapeGeometry(Dali::Texture blendShapeGeometry)
237 mBlendShapeGeometry = blendShapeGeometry;
240 void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents)
242 mHasPositions = hasPositions;
243 mHasNormals = hasNormals;
244 mHasTangents = hasTangents;
247 void ModelPrimitive::SetSkinned(bool isSkinned)
249 mHasSkinning = isSkinned;
252 // From MaterialModifyObserver
254 void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, MaterialModifyObserver::ModifyFlag flag)
256 ApplyMaterialToRenderer(flag);
259 void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
261 uint32_t shaderFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER));
262 if(mIsMaterialChanged || shaderFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER))
264 std::string vertexShader = GetImplementation(mMaterial).GetVertexShader();
265 std::string fragmentShader = GetImplementation(mMaterial).GetFragmentShader();
267 std::vector<std::string> defines;
268 defines.push_back("VEC4_TANGENT");
271 defines.push_back("SKINNING");
273 if(mHasPositions || mHasNormals || mHasTangents)
277 defines.push_back(MORPH_POSITION_KEYWORD.data());
281 defines.push_back(MORPH_NORMAL_KEYWORD.data());
285 defines.push_back(MORPH_TANGENT_KEYWORD.data());
287 defines.push_back(MORPH_KEYWORD.data());
288 if(mBlendShapeData.version == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
290 defines.push_back(MORPH_VERSION_2_0_KEYWORD.data());
293 for(const auto& define : defines)
295 Scene3D::Loader::ShaderDefinition::ApplyDefine(vertexShader, define);
299 mShader = Shader::New(vertexShader, fragmentShader);
307 mRenderer.SetShader(mShader);
311 uint32_t textureFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE));
312 if(mIsMaterialChanged || textureFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE))
314 mTextureSet = GetImplementation(mMaterial).GetTextureSet();
316 if(mBlendShapeGeometry)
318 TextureSet newTextureSet = TextureSet::New();
319 newTextureSet.SetTexture(0u, mBlendShapeGeometry);
321 const unsigned int numberOfTextures = mTextureSet.GetTextureCount();
322 for(unsigned int index = 0u; index < numberOfTextures; ++index)
324 const unsigned int newIndex = index + 1u;
325 newTextureSet.SetTexture(newIndex, mTextureSet.GetTexture(index));
326 newTextureSet.SetSampler(newIndex, mTextureSet.GetSampler(index));
329 mTextureSet = newTextureSet;
332 uint32_t textureCount = mTextureSet.GetTextureCount();
333 Texture brdfTexture = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
334 if(!mSpecularTexture || !mDiffuseTexture)
336 Scene3D::Loader::EnvironmentMapData environmentMapData;
337 environmentMapData.mPixelData.resize(6);
338 for(auto& face : environmentMapData.mPixelData)
340 face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
342 environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP);
343 Texture iblTexture = environmentMapData.GetTexture();
344 mDiffuseTexture = iblTexture;
345 mSpecularTexture = iblTexture;
348 mTextureSet.SetTexture(textureCount++, brdfTexture);
349 mTextureSet.SetTexture(textureCount++, mDiffuseTexture);
350 mTextureSet.SetTexture(textureCount, mSpecularTexture);
352 auto specularSampler = Sampler::New();
353 specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
354 specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
355 mTextureSet.SetSampler(textureCount, specularSampler);
363 mRenderer.SetTextures(mTextureSet);
367 uint32_t uniformFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM));
368 if(mIsMaterialChanged || uniformFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM))
372 mNeedToSetRendererUniform = true;
376 UpdateRendererUniform();
379 mIsMaterialChanged = false;
382 void ModelPrimitive::CreateRenderer()
384 if(!mShader || !mGeometry || !mTextureSet || mRenderer)
389 mRenderer = Renderer::New(mGeometry, mShader);
390 mRenderer.SetTextures(mTextureSet);
391 UpdateRendererUniform();
393 uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
394 for(uint32_t i = 0; i < maxLightCount; ++i)
398 AddLight(mLights[i], i);
402 for(auto* observer : mObservers)
404 observer->OnRendererCreated(mRenderer);
408 void ModelPrimitive::UpdateImageBasedLightTexture()
410 if(mRenderer && mMaterial)
412 Dali::TextureSet textures = mRenderer.GetTextures();
418 uint32_t textureCount = textures.GetTextureCount();
419 if(textureCount > 2u &&
420 (textures.GetTexture(textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset()) != mDiffuseTexture ||
421 textures.GetTexture(textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset()) != mSpecularTexture))
423 Dali::TextureSet newTextures = Dali::TextureSet::New();
425 for(uint32_t index = 0u; index < textureCount; ++index)
427 Dali::Texture texture = textures.GetTexture(index);
428 if(index == textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset())
430 texture = mDiffuseTexture;
432 else if(index == textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset())
434 texture = mSpecularTexture;
437 newTextures.SetTexture(index, texture);
438 newTextures.SetSampler(index, textures.GetSampler(index));
441 mRenderer.SetTextures(newTextures);
443 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
444 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
448 void ModelPrimitive::UpdateRendererUniform()
450 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
451 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
452 GetImplementation(mMaterial).SetRendererUniform(mRenderer);
455 } // namespace Internal
457 } // namespace Scene3D