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_POSITION_KEYWORD = "MORPH_POSITION";
53 constexpr std::string_view MORPH_NORMAL_KEYWORD = "MORPH_NORMAL";
54 constexpr std::string_view MORPH_TANGENT_KEYWORD = "MORPH_TANGENT";
55 constexpr std::string_view MORPH_VERSION_2_0_KEYWORD = "MORPH_VERSION_2_0";
57 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
58 } // unnamed namespace
60 ModelPrimitivePtr ModelPrimitive::New()
62 ModelPrimitivePtr primitive = new ModelPrimitive();
64 primitive->Initialize();
69 ModelPrimitive::ModelPrimitive()
73 ModelPrimitive::~ModelPrimitive()
77 GetImplementation(mMaterial).RemoveObserver(this);
82 void ModelPrimitive::Initialize()
84 mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount());
87 void ModelPrimitive::SetRenderer(Dali::Renderer renderer)
90 mGeometry = renderer.GetGeometry();
91 mTextureSet = renderer.GetTextures();
92 mShader = renderer.GetShader();
95 Dali::Renderer ModelPrimitive::GetRenderer() const
100 void ModelPrimitive::SetGeometry(Dali::Geometry geometry)
102 mGeometry = geometry;
106 Dali::Geometry ModelPrimitive::GetGeometry() const
111 void ModelPrimitive::SetMaterial(Dali::Scene3D::Material material, bool updateRenderer)
118 if(mMaterial != material)
120 // Stop observe from previous material.
123 GetImplementation(mMaterial).RemoveObserver(this);
126 mMaterial = material;
128 // Start observe from new material.
132 GetImplementation(mMaterial).AddObserver(this);
137 mIsMaterialChanged = true;
138 if(GetImplementation(mMaterial).IsResourceReady())
140 GetImplementation(mMaterial).UpdateMaterialData();
141 ApplyMaterialToRenderer();
144 UpdateImageBasedLightTexture();
148 Dali::Scene3D::Material ModelPrimitive::GetMaterial() const
153 void ModelPrimitive::AddPrimitiveObserver(ModelPrimitiveModifyObserver* observer)
155 mObservers.insert(observer);
158 void ModelPrimitive::RemovePrimitiveObserver(ModelPrimitiveModifyObserver* observer)
160 mObservers.erase(observer);
163 void ModelPrimitive::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
165 mDiffuseTexture = diffuseTexture;
166 mSpecularTexture = specularTexture;
167 mIblScaleFactor = iblScaleFactor;
168 mSpecularMipmapLevels = specularMipmapLevels;
170 UpdateImageBasedLightTexture();
173 void ModelPrimitive::SetImageBasedLightScaleFactor(float iblScaleFactor)
175 mIblScaleFactor = iblScaleFactor;
176 if(mRenderer && mMaterial)
178 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), iblScaleFactor);
182 void ModelPrimitive::AddLight(Scene3D::Light light, uint32_t lightIndex)
184 if(mLights[lightIndex])
186 RemoveLight(lightIndex);
189 mLights[lightIndex] = light;
190 // TODO Remove light at lightIndex if it is already set.
191 if(mRenderer && mMaterial)
194 std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
195 mRenderer.RegisterProperty(lightCountPropertyName, mLightCount);
197 std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
198 lightDirectionPropertyName += "[" + std::to_string(lightIndex) + "]";
199 auto lightDirectionPropertyIndex = mRenderer.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
200 Dali::Constraint lightDirectionConstraint = Dali::Constraint::New<Vector3>(mRenderer, lightDirectionPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs)
201 { output = inputs[0]->GetQuaternion().Rotate(Vector3::ZAXIS); });
202 lightDirectionConstraint.AddSource(Source{light, Dali::Actor::Property::WORLD_ORIENTATION});
203 lightDirectionConstraint.ApplyPost();
204 lightDirectionConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
206 std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
207 lightColorPropertyName += "[" + std::to_string(lightIndex) + "]";
208 auto lightColorPropertyIndex = mRenderer.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
209 Dali::Constraint lightColorConstraint = Dali::Constraint::New<Vector3>(mRenderer, lightColorPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs)
210 { output = Vector3(inputs[0]->GetVector4()); });
211 lightColorConstraint.AddSource(Source{light, Dali::Actor::Property::COLOR});
212 lightColorConstraint.ApplyPost();
213 lightColorConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
217 void ModelPrimitive::RemoveLight(uint32_t lightIndex)
220 std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
221 mRenderer.RegisterProperty(lightCountPropertyName, mLightCount);
223 mRenderer.RemoveConstraints(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
225 mLights[lightIndex].Reset();
228 void ModelPrimitive::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data)
230 mBlendShapeData = std::move(data);
231 Scene3D::Loader::BlendShapes::ConfigureProperties(mBlendShapeData, mRenderer);
234 void ModelPrimitive::SetBlendShapeGeometry(Dali::Texture blendShapeGeometry)
236 mBlendShapeGeometry = blendShapeGeometry;
239 void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents)
241 mHasPositions = hasPositions;
242 mHasNormals = hasNormals;
243 mHasTangents = hasTangents;
246 void ModelPrimitive::SetSkinned(bool isSkinned)
248 mHasSkinning = isSkinned;
251 // From MaterialModifyObserver
253 void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, MaterialModifyObserver::ModifyFlag flag)
255 ApplyMaterialToRenderer(flag);
258 void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
260 uint32_t shaderFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER));
261 if(mIsMaterialChanged || shaderFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER))
263 std::string vertexShader = GetImplementation(mMaterial).GetVertexShader();
264 std::string fragmentShader = GetImplementation(mMaterial).GetFragmentShader();
266 std::vector<std::string> defines;
267 defines.push_back("VEC4_TANGENT");
270 defines.push_back("SKINNING");
272 if(mHasPositions || mHasNormals || mHasTangents)
276 defines.push_back(MORPH_POSITION_KEYWORD.data());
280 defines.push_back(MORPH_NORMAL_KEYWORD.data());
284 defines.push_back(MORPH_TANGENT_KEYWORD.data());
286 if(mBlendShapeData.version == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
288 defines.push_back(MORPH_VERSION_2_0_KEYWORD.data());
291 for(const auto& define : defines)
293 Scene3D::Loader::ShaderDefinition::ApplyDefine(vertexShader, define);
297 mShader = Shader::New(vertexShader, fragmentShader);
305 mRenderer.SetShader(mShader);
309 uint32_t textureFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE));
310 if(mIsMaterialChanged || textureFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::TEXTURE))
312 mTextureSet = GetImplementation(mMaterial).GetTextureSet();
314 if(mBlendShapeGeometry)
316 TextureSet newTextureSet = TextureSet::New();
317 newTextureSet.SetTexture(0u, mBlendShapeGeometry);
319 const unsigned int numberOfTextures = mTextureSet.GetTextureCount();
320 for(unsigned int index = 0u; index < numberOfTextures; ++index)
322 const unsigned int newIndex = index + 1u;
323 newTextureSet.SetTexture(newIndex, mTextureSet.GetTexture(index));
324 newTextureSet.SetSampler(newIndex, mTextureSet.GetSampler(index));
327 mTextureSet = newTextureSet;
330 uint32_t textureCount = mTextureSet.GetTextureCount();
331 Texture brdfTexture = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
332 if(!mSpecularTexture || !mDiffuseTexture)
334 Scene3D::Loader::EnvironmentMapData environmentMapData;
335 environmentMapData.mPixelData.resize(6);
336 for(auto& face : environmentMapData.mPixelData)
338 face.push_back(PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY));
340 environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP);
341 Texture iblTexture = environmentMapData.GetTexture();
342 mDiffuseTexture = iblTexture;
343 mSpecularTexture = iblTexture;
346 mTextureSet.SetTexture(textureCount++, brdfTexture);
347 mTextureSet.SetTexture(textureCount++, mDiffuseTexture);
348 mTextureSet.SetTexture(textureCount, mSpecularTexture);
350 auto specularSampler = Sampler::New();
351 specularSampler.SetWrapMode(WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE);
352 specularSampler.SetFilterMode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR);
353 mTextureSet.SetSampler(textureCount, specularSampler);
361 mRenderer.SetTextures(mTextureSet);
365 uint32_t uniformFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM));
366 if(mIsMaterialChanged || uniformFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::UNIFORM))
370 mNeedToSetRendererUniform = true;
374 UpdateRendererUniform();
377 mIsMaterialChanged = false;
380 void ModelPrimitive::CreateRenderer()
382 if(!mShader || !mGeometry || !mTextureSet || mRenderer)
387 mRenderer = Renderer::New(mGeometry, mShader);
388 mRenderer.SetTextures(mTextureSet);
389 UpdateRendererUniform();
391 uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
392 for(uint32_t i = 0; i < maxLightCount; ++i)
396 AddLight(mLights[i], i);
400 for(auto* observer : mObservers)
402 observer->OnRendererCreated(mRenderer);
406 void ModelPrimitive::UpdateImageBasedLightTexture()
408 if(mRenderer && mMaterial)
410 Dali::TextureSet textures = mRenderer.GetTextures();
416 uint32_t textureCount = textures.GetTextureCount();
417 if(textureCount > 2u &&
418 (textures.GetTexture(textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset()) != mDiffuseTexture ||
419 textures.GetTexture(textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset()) != mSpecularTexture))
421 Dali::TextureSet newTextures = Dali::TextureSet::New();
423 for(uint32_t index = 0u; index < textureCount; ++index)
425 Dali::Texture texture = textures.GetTexture(index);
426 if(index == textureCount - GetImplementation(mMaterial).GetDiffuseImageBasedLightTextureOffset())
428 texture = mDiffuseTexture;
430 else if(index == textureCount - GetImplementation(mMaterial).GetSpecularImageBasedLightTextureOffset())
432 texture = mSpecularTexture;
435 newTextures.SetTexture(index, texture);
436 newTextures.SetSampler(index, textures.GetSampler(index));
439 mRenderer.SetTextures(newTextures);
441 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
442 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
446 void ModelPrimitive::UpdateRendererUniform()
448 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
449 mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
450 GetImplementation(mMaterial).SetRendererUniform(mRenderer);
453 } // namespace Internal
455 } // namespace Scene3D