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>
32 #include <dali/integration-api/debug.h>
43 * Creates control through type registry
47 return Scene3D::ModelPrimitive::New();
50 // Setup properties, signals and actions using the type-registry.
51 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelPrimitive, Dali::BaseHandle, Create);
52 DALI_TYPE_REGISTRATION_END()
54 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
55 } // unnamed namespace
57 ModelPrimitivePtr ModelPrimitive::New()
59 ModelPrimitivePtr primitive = new ModelPrimitive();
61 primitive->Initialize();
66 ModelPrimitive::ModelPrimitive()
67 : mShaderManager(new Scene3D::Loader::ShaderManager())
71 ModelPrimitive::~ModelPrimitive()
75 GetImplementation(mMaterial).RemoveObserver(this);
80 void ModelPrimitive::Initialize()
82 mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount());
85 void ModelPrimitive::SetRenderer(Dali::Renderer renderer)
88 mGeometry = renderer.GetGeometry();
89 mTextureSet = renderer.GetTextures();
90 mShader = renderer.GetShader();
93 Dali::Renderer ModelPrimitive::GetRenderer() const
98 void ModelPrimitive::SetGeometry(Dali::Geometry geometry)
100 mGeometry = geometry;
104 Dali::Geometry ModelPrimitive::GetGeometry() const
109 void ModelPrimitive::SetMaterial(Dali::Scene3D::Material material, bool updateRenderer)
116 if(mMaterial != material)
118 // Stop observe from previous material.
121 GetImplementation(mMaterial).RemoveObserver(this);
124 mMaterial = material;
126 // Start observe from new material.
130 GetImplementation(mMaterial).AddObserver(this);
135 mIsMaterialChanged = true;
136 if(GetImplementation(mMaterial).IsResourceReady())
138 GetImplementation(mMaterial).UpdateMaterialData();
139 ApplyMaterialToRenderer();
142 UpdateImageBasedLightTexture();
146 Dali::Scene3D::Material ModelPrimitive::GetMaterial() const
151 void ModelPrimitive::AddPrimitiveObserver(ModelPrimitiveModifyObserver* observer)
153 mObservers.insert(observer);
156 void ModelPrimitive::RemovePrimitiveObserver(ModelPrimitiveModifyObserver* observer)
158 mObservers.erase(observer);
161 void ModelPrimitive::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
163 mDiffuseTexture = diffuseTexture;
164 mSpecularTexture = specularTexture;
165 mIblScaleFactor = iblScaleFactor;
166 mSpecularMipmapLevels = specularMipmapLevels;
168 UpdateImageBasedLightTexture();
171 void ModelPrimitive::SetImageBasedLightScaleFactor(float iblScaleFactor)
173 mIblScaleFactor = iblScaleFactor;
174 if(mRenderer && mMaterial)
176 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), iblScaleFactor);
180 void ModelPrimitive::AddLight(Scene3D::Light light, uint32_t lightIndex)
182 if(mLights[lightIndex])
184 RemoveLight(lightIndex);
187 mLights[lightIndex] = light;
188 // TODO Remove light at lightIndex if it is already set.
189 if(mRenderer && mMaterial)
192 std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
193 mRenderer.RegisterProperty(lightCountPropertyName, mLightCount);
195 std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
196 lightDirectionPropertyName += "[" + std::to_string(lightIndex) + "]";
197 auto lightDirectionPropertyIndex = mRenderer.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
198 Dali::Constraint lightDirectionConstraint = Dali::Constraint::New<Vector3>(mRenderer, lightDirectionPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs)
199 { output = inputs[0]->GetQuaternion().Rotate(Vector3::ZAXIS); });
200 lightDirectionConstraint.AddSource(Source{light, Dali::Actor::Property::WORLD_ORIENTATION});
201 lightDirectionConstraint.ApplyPost();
202 lightDirectionConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
204 std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
205 lightColorPropertyName += "[" + std::to_string(lightIndex) + "]";
206 auto lightColorPropertyIndex = mRenderer.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
207 Dali::Constraint lightColorConstraint = Dali::Constraint::New<Vector3>(mRenderer, lightColorPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs)
208 { output = Vector3(inputs[0]->GetVector4()); });
209 lightColorConstraint.AddSource(Source{light, Dali::Actor::Property::COLOR});
210 lightColorConstraint.ApplyPost();
211 lightColorConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
215 void ModelPrimitive::RemoveLight(uint32_t lightIndex)
218 std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
219 mRenderer.RegisterProperty(lightCountPropertyName, mLightCount);
221 mRenderer.RemoveConstraints(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
223 mLights[lightIndex].Reset();
226 void ModelPrimitive::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
228 if(mShaderManager != shaderManager)
230 mShaderManager = (shaderManager) ? shaderManager : new Scene3D::Loader::ShaderManager();
231 if(mMaterial && GetImplementation(mMaterial).IsResourceReady())
233 ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag::SHADER);
238 void ModelPrimitive::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data)
240 mBlendShapeData = std::move(data);
241 Scene3D::Loader::BlendShapes::ConfigureProperties(mBlendShapeData, mRenderer);
244 void ModelPrimitive::SetBlendShapeGeometry(Dali::Texture blendShapeGeometry)
246 mBlendShapeGeometry = blendShapeGeometry;
249 void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents, Scene3D::Loader::BlendShapes::Version version)
251 mHasPositions = hasPositions;
252 mHasNormals = hasNormals;
253 mHasTangents = hasTangents;
254 mBlendShapeVersion = version;
257 void ModelPrimitive::SetSkinned(bool isSkinned)
259 mHasSkinning = isSkinned;
262 // From MaterialModifyObserver
264 void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, MaterialModifyObserver::ModifyFlag flag)
266 ApplyMaterialToRenderer(flag);
269 void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
276 uint32_t shaderFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER));
277 if(mIsMaterialChanged || shaderFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER))
279 Scene3D::Loader::ShaderOption shaderOption = GetImplementation(mMaterial).GetShaderOption();
281 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::VEC4_TANGENT);
284 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::SKINNING);
286 if(mHasPositions || mHasNormals || mHasTangents)
290 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_POSITION);
294 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_NORMAL);
298 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_TANGENT);
300 if(mBlendShapeVersion == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
302 shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_VERSION_2_0);
307 mShader = mShaderManager->ProduceShader(shaderOption);
315 mRenderer.SetShader(mShader);
319 uint32_t textureFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE));
320 if(mIsMaterialChanged || textureFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE))
322 mTextureSet = GetImplementation(mMaterial).GetTextureSet();
324 if(mBlendShapeGeometry)
326 TextureSet newTextureSet = TextureSet::New();
327 newTextureSet.SetTexture(0u, mBlendShapeGeometry);
329 const unsigned int numberOfTextures = mTextureSet.GetTextureCount();
330 for(unsigned int index = 0u; index < numberOfTextures; ++index)
332 const unsigned int newIndex = index + 1u;
333 newTextureSet.SetTexture(newIndex, mTextureSet.GetTexture(index));
334 newTextureSet.SetSampler(newIndex, mTextureSet.GetSampler(index));
337 mTextureSet = newTextureSet;
340 uint32_t textureCount = mTextureSet.GetTextureCount();
341 Texture brdfTexture = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
342 if(!mSpecularTexture || !mDiffuseTexture)
344 Scene3D::Loader::EnvironmentMapData environmentMapData;
345 environmentMapData.mPixelData.resize(6);
346 for(auto& face : environmentMapData.mPixelData)
348 face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
350 environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP);
351 Texture iblTexture = environmentMapData.GetTexture();
352 mDiffuseTexture = iblTexture;
353 mSpecularTexture = iblTexture;
356 mTextureSet.SetTexture(textureCount++, brdfTexture);
357 mTextureSet.SetTexture(textureCount++, mDiffuseTexture);
358 mTextureSet.SetTexture(textureCount, mSpecularTexture);
360 auto specularSampler = Sampler::New();
361 specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
362 specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
363 mTextureSet.SetSampler(textureCount, specularSampler);
371 mRenderer.SetTextures(mTextureSet);
375 uint32_t uniformFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM));
376 if(mIsMaterialChanged || uniformFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM))
380 mNeedToSetRendererUniform = true;
384 UpdateRendererUniform();
387 mIsMaterialChanged = false;
390 void ModelPrimitive::CreateRenderer()
392 if(!mShader || !mGeometry || !mTextureSet || mRenderer)
397 mRenderer = Renderer::New(mGeometry, mShader);
398 mRenderer.SetTextures(mTextureSet);
399 UpdateRendererUniform();
401 uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
402 for(uint32_t i = 0; i < maxLightCount; ++i)
406 AddLight(mLights[i], i);
410 for(auto* observer : mObservers)
412 observer->OnRendererCreated(mRenderer);
416 void ModelPrimitive::UpdateImageBasedLightTexture()
418 if(mRenderer && mMaterial)
420 Dali::TextureSet textures = mRenderer.GetTextures();
426 uint32_t textureCount = textures.GetTextureCount();
427 if(textureCount > 2u &&
428 (textures.GetTexture(textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset()) != mDiffuseTexture ||
429 textures.GetTexture(textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset()) != mSpecularTexture))
431 Dali::TextureSet newTextures = Dali::TextureSet::New();
433 for(uint32_t index = 0u; index < textureCount; ++index)
435 Dali::Texture texture = textures.GetTexture(index);
436 if(index == textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset())
438 texture = mDiffuseTexture;
440 else if(index == textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset())
442 texture = mSpecularTexture;
445 newTextures.SetTexture(index, texture);
446 newTextures.SetSampler(index, textures.GetSampler(index));
449 mRenderer.SetTextures(newTextures);
451 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
452 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
456 void ModelPrimitive::UpdateRendererUniform()
460 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
461 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
462 GetImplementation(mMaterial).SetRendererUniform(mRenderer);
466 } // namespace Internal
468 } // namespace Scene3D