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/controls/model/model-impl.h>
22 #include <dali-toolkit/dali-toolkit.h>
23 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
24 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
25 #include <dali/devel-api/actors/actor-devel.h>
26 #include <dali/integration-api/adaptor-framework/adaptor.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/public-api/math/math-utils.h>
29 #include <dali/public-api/object/type-registry-helper.h>
30 #include <dali/public-api/object/type-registry.h>
34 #include <dali-scene3d/internal/common/model-cache-manager.h>
35 #include <dali-scene3d/internal/controls/scene-view/scene-view-impl.h>
36 #include <dali-scene3d/internal/light/light-impl.h>
37 #include <dali-scene3d/internal/model-components/model-node-impl.h>
38 #include <dali-scene3d/public-api/controls/model/model.h>
39 #include <dali-scene3d/public-api/loader/animation-definition.h>
40 #include <dali-scene3d/public-api/loader/camera-parameters.h>
41 #include <dali-scene3d/public-api/loader/light-parameters.h>
42 #include <dali-scene3d/public-api/loader/load-result.h>
43 #include <dali-scene3d/public-api/loader/node-definition.h>
44 #include <dali-scene3d/public-api/loader/scene-definition.h>
45 #include <dali-scene3d/public-api/loader/shader-definition-factory.h>
58 * Creates control through type registry
62 return Scene3D::Model::New(std::string());
65 // Setup properties, signals and actions using the type-registry.
66 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Model, Toolkit::Control, Create);
67 DALI_TYPE_REGISTRATION_END()
69 static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f);
70 static constexpr float SIZE_STEP_CONDITION = 0.1f;
72 static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false;
73 static constexpr bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false;
79 pointMin = Vector3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
80 pointMax = Vector3(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
83 void ConsiderNewPointInVolume(const Vector3& position)
85 pointMin.x = std::min(position.x, pointMin.x);
86 pointMin.y = std::min(position.y, pointMin.y);
87 pointMin.z = std::min(position.z, pointMin.z);
89 pointMax.x = std::max(position.x, pointMax.x);
90 pointMax.y = std::max(position.y, pointMax.y);
91 pointMax.z = std::max(position.z, pointMax.z);
94 Vector3 CalculateSize()
96 return pointMax - pointMin;
99 Vector3 CalculatePivot()
101 Vector3 pivot = pointMin / (pointMin - pointMax);
102 for(uint32_t i = 0; i < 3; ++i)
104 // To avoid divid by zero
105 if(Dali::Equals(pointMin[i], pointMax[i]))
117 void ConfigureBlendShapeShaders(
118 Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
120 std::vector<std::string> errors;
121 auto onError = [&errors](const std::string& msg) { errors.push_back(msg); };
122 if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
124 Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
125 for(auto& msg : errors)
127 flinger << msg << '\n';
132 void AddModelTreeToAABB(BoundingVolume& AABB, const Dali::Scene3D::Loader::SceneDefinition& scene, const Dali::Scene3D::Loader::Customization::Choices& choices, Dali::Scene3D::Loader::Index iNode, Dali::Scene3D::Loader::NodeDefinition::CreateParams& nodeParams, Matrix parentMatrix)
134 static constexpr uint32_t BOX_POINT_COUNT = 8;
135 static uint32_t BBIndex[BOX_POINT_COUNT][3] = {{0, 0, 0}, {0, 1, 0}, {1, 0, 0}, {1, 1, 0}, {0, 0, 1}, {0, 1, 1}, {1, 0, 1}, {1, 1, 1}};
138 const Dali::Scene3D::Loader::NodeDefinition* node = scene.GetNode(iNode);
139 Matrix localMatrix = node->GetLocalSpace();
140 Matrix::Multiply(nodeMatrix, localMatrix, parentMatrix);
143 if(node->GetExtents(nodeParams.mResources, volume[0], volume[1]))
145 for(uint32_t i = 0; i < BOX_POINT_COUNT; ++i)
147 Vector4 position = Vector4(volume[BBIndex[i][0]].x, volume[BBIndex[i][1]].y, volume[BBIndex[i][2]].z, 1.0f);
148 Vector4 objectPosition = nodeMatrix * position;
149 objectPosition /= objectPosition.w;
151 AABB.ConsiderNewPointInVolume(Vector3(objectPosition));
155 if(node->mCustomization)
157 if(!node->mChildren.empty())
159 auto choice = choices.Get(node->mCustomization->mTag);
160 Dali::Scene3D::Loader::Index i = std::min(choice != Dali::Scene3D::Loader::Customization::NONE ? choice : 0, static_cast<Dali::Scene3D::Loader::Index>(node->mChildren.size() - 1));
162 AddModelTreeToAABB(AABB, scene, choices, node->mChildren[i], nodeParams, nodeMatrix);
167 for(auto i : node->mChildren)
169 AddModelTreeToAABB(AABB, scene, choices, i, nodeParams, nodeMatrix);
174 void AddLightRecursively(Scene3D::ModelNode node, Scene3D::Light light, uint32_t lightIndex)
180 GetImplementation(node).AddLight(light, lightIndex);
182 uint32_t childrenCount = node.GetChildCount();
183 for(uint32_t i = 0; i < childrenCount; ++i)
185 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
188 AddLightRecursively(childNode, light, lightIndex);
193 void RemoveLightRecursively(Scene3D::ModelNode node, uint32_t lightIndex)
200 GetImplementation(node).RemoveLight(lightIndex);
202 uint32_t childrenCount = node.GetChildCount();
203 for(uint32_t i = 0; i < childrenCount; ++i)
205 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
208 RemoveLightRecursively(childNode, lightIndex);
213 void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node)
219 const auto childCount = node.GetChildCount();
220 for(auto i = 0u; i < childCount; ++i)
222 UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i)));
225 std::vector<std::string> blendShapeNames;
226 node.RetrieveBlendShapeNames(blendShapeNames);
227 for(const auto& iter : blendShapeNames)
229 // Append or create new list.
230 resultMap[iter].push_back(node);
234 } // anonymous namespace
236 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
237 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
239 mResourceDirectoryUrl(resourceDirectoryUrl),
241 mNaturalSize(Vector3::ZERO),
242 mModelPivot(AnchorPoint::CENTER),
243 mSceneIblScaleFactor(1.0f),
244 mIblScaleFactor(1.0f),
245 mSceneSpecularMipmapLevels(1u),
246 mSpecularMipmapLevels(1u),
247 mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE),
248 mModelChildrenFocusable(DEFAULT_MODEL_CHILDREN_FOCUSABLE),
249 mModelResourceReady(false),
250 mIblDiffuseResourceReady(true),
251 mIblSpecularResourceReady(true),
252 mIblDiffuseDirty(false),
253 mIblSpecularDirty(false)
259 ResetResourceTasks();
261 if(ModelCacheManager::Get() && !mModelUrl.empty())
263 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
267 Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
269 Model* impl = new Model(modelUrl, resourceDirectoryUrl);
271 Dali::Scene3D::Model handle = Dali::Scene3D::Model(*impl);
273 // Second-phase init of the implementation
274 // This can only be done after the CustomActor connection has been made...
280 const Scene3D::ModelNode Model::GetModelRoot() const
285 void Model::AddModelNode(Scene3D::ModelNode modelNode)
292 mModelRoot.Add(modelNode);
293 if(mModelUrl.empty())
295 mModelResourceReady = true;
298 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
300 UpdateImageBasedLightTexture();
301 UpdateImageBasedLightScaleFactor();
304 uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
305 for(uint32_t i = 0; i < maxLightCount; ++i)
309 AddLightRecursively(modelNode, mLights[i], i);
313 if(Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
315 NotifyResourceReady();
319 void Model::RemoveModelNode(Scene3D::ModelNode modelNode)
323 uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
324 for(uint32_t i = 0; i < maxLightCount; ++i)
328 RemoveLightRecursively(modelNode, i);
331 mModelRoot.Remove(modelNode);
335 void Model::SetChildrenSensitive(bool enable)
337 if(mModelChildrenSensitive != enable)
339 mModelChildrenSensitive = enable;
342 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
347 bool Model::GetChildrenSensitive() const
349 return mModelChildrenSensitive;
352 void Model::SetChildrenFocusable(bool enable)
354 if(mModelChildrenFocusable != enable)
356 mModelChildrenFocusable = enable;
359 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
360 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
365 bool Model::GetChildrenFocusable() const
367 return mModelChildrenFocusable;
370 void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
372 bool needIblReset = false;
373 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
374 if(mDiffuseIblUrl != diffuseUrl)
376 mDiffuseIblUrl = diffuseUrl;
377 if(mDiffuseIblUrl.empty())
383 mIblDiffuseDirty = true;
384 mIblDiffuseResourceReady = false;
388 if(mSpecularIblUrl != specularUrl)
390 mSpecularIblUrl = specularUrl;
391 if(mSpecularIblUrl.empty())
397 mIblSpecularDirty = true;
398 mIblSpecularResourceReady = false;
402 // If one or both of diffuse url and specular url are empty,
403 // we don't need to request to load texture.
406 ResetResourceTask(mIblDiffuseLoadTask);
407 ResetResourceTask(mIblSpecularLoadTask);
409 mIblDiffuseDirty = false;
410 mIblSpecularDirty = false;
411 mIblDiffuseResourceReady = true;
412 mIblSpecularResourceReady = true;
414 mDiffuseTexture.Reset();
415 mSpecularTexture.Reset();
416 UpdateImageBasedLightTexture();
420 if(isOnScene && mIblDiffuseDirty)
422 ResetResourceTask(mIblDiffuseLoadTask);
423 mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete));
424 Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
425 mIblDiffuseDirty = false;
428 if(isOnScene && mIblSpecularDirty)
430 ResetResourceTask(mIblSpecularLoadTask);
431 mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete));
432 Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
433 mIblSpecularDirty = false;
437 if(!Dali::Equals(mIblScaleFactor, scaleFactor))
439 mIblScaleFactor = scaleFactor;
440 UpdateImageBasedLightScaleFactor();
443 // If diffuse and specular textures are already loaded, emits resource ready signal here.
444 NotifyResourceReady();
447 void Model::SetImageBasedLightScaleFactor(float scaleFactor)
449 mIblScaleFactor = scaleFactor;
450 if(mDiffuseTexture && mSpecularTexture)
452 UpdateImageBasedLightScaleFactor();
456 float Model::GetImageBasedLightScaleFactor() const
458 return mIblScaleFactor;
461 uint32_t Model::GetAnimationCount() const
463 return mAnimations.size();
466 Dali::Animation Model::GetAnimation(uint32_t index) const
468 Dali::Animation animation;
469 if(mAnimations.size() > index)
471 animation = mAnimations[index].second;
476 Dali::Animation Model::GetAnimation(const std::string& name) const
478 Dali::Animation animation;
481 for(auto&& animationData : mAnimations)
483 if(animationData.first == name)
485 animation = animationData.second;
493 uint32_t Model::GetCameraCount() const
495 return mCameraParameters.size();
498 Dali::CameraActor Model::GenerateCamera(uint32_t index) const
500 Dali::CameraActor camera;
501 if(mCameraParameters.size() > index)
503 camera = Dali::CameraActor::New3DCamera();
504 if(!mCameraParameters[index].ConfigureCamera(camera, false))
506 DALI_LOG_ERROR("Fail to generate %u's camera actor : Some property was not defined. Please check model file.\n", index);
511 ApplyCameraTransform(camera);
516 bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const
518 if(camera && mCameraParameters.size() > index)
520 if(!mCameraParameters[index].ConfigureCamera(camera, false))
522 DALI_LOG_ERROR("Fail to apply %u's camera actor : Some property was not defined. Please check model file.\n", index);
526 ApplyCameraTransform(camera);
532 Scene3D::ModelNode Model::FindChildModelNodeByName(std::string_view nodeName)
534 Actor childActor = Self().FindChildByName(nodeName);
535 return Scene3D::ModelNode::DownCast(childActor);
538 void Model::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
540 blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeModelNodeMap.size());
541 for(const auto& iter : mBlendShapeModelNodeMap)
543 blendShapeNames.push_back(iter.first);
547 void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<Scene3D::ModelNode>& modelNodes) const
549 auto iter = mBlendShapeModelNodeMap.find(std::string(blendShapeName));
550 if(iter != mBlendShapeModelNodeMap.end())
552 const auto& modelNodeList = iter->second;
553 modelNodes.reserve(modelNodes.size() + modelNodeList.size());
554 for(const auto& nodeIter : modelNodeList)
556 modelNodes.push_back(nodeIter);
561 ///////////////////////////////////////////////////////////
566 void Model::OnInitialize()
568 // Make ParentOrigin as Center.
569 Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
570 mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount());
573 void Model::OnSceneConnection(int depth)
575 if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty())
577 // Request model load only if we setup url.
578 if(ModelCacheManager::Get())
580 ModelCacheManager::Get().ReferenceModelCache(mModelUrl);
582 mModelLoadTask = new ModelLoadTask(mModelUrl, mResourceDirectoryUrl, MakeCallback(this, &Model::OnModelLoadComplete));
583 Dali::AsyncTaskManager::Get().AddTask(mModelLoadTask);
586 // If diffuse and specular url is not valid, IBL does not need to be loaded.
587 if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
589 SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
592 Actor parent = Self().GetParent();
595 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
598 GetImpl(sceneView).RegisterSceneItem(this);
599 mParentSceneView = sceneView;
602 parent = parent.GetParent();
605 NotifyResourceReady();
607 mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION));
608 mSizeNotification.NotifySignal().Connect(this, &Model::OnSizeNotification);
609 Control::OnSceneConnection(depth);
612 void Model::OnSceneDisconnection()
614 Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
617 GetImpl(sceneView).UnregisterSceneItem(this);
618 mParentSceneView.Reset();
621 mSizeNotification.NotifySignal().Disconnect(this, &Model::OnSizeNotification);
622 Self().RemovePropertyNotification(mSizeNotification);
623 mSizeNotification.Reset();
625 Control::OnSceneDisconnection();
628 void Model::OnSizeSet(const Vector3& size)
633 Vector3 Model::GetNaturalSize()
637 DALI_LOG_ERROR("Model is still not loaded.\n");
638 return Vector3::ZERO;
644 float Model::GetHeightForWidth(float width)
647 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
648 return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
651 float Model::GetWidthForHeight(float height)
654 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
655 return Control::GetWidthForHeight(height) + padding.start + padding.end;
658 void Model::OnRelayout(const Vector2& size, RelayoutContainer& container)
660 Control::OnRelayout(size, container);
664 bool Model::IsResourceReady() const
666 return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady;
669 void Model::CreateModelRoot()
671 mModelRoot = Scene3D::ModelNode::New();
672 mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
673 mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION);
674 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
675 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
676 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
677 Self().Add(mModelRoot);
680 void Model::ScaleModel(bool useCurrentSize)
688 Vector3 size = (useCurrentSize) ? Self().GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE) : Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
689 if(size.x > 0.0f && size.y > 0.0f)
692 scale = std::min(size.x / mNaturalSize.x, scale);
693 scale = std::min(size.y / mNaturalSize.y, scale);
695 // Models in glTF and dli are defined as right hand coordinate system.
696 // DALi uses left hand coordinate system. Scaling negative is for change winding order.
697 mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale);
700 void Model::FitModelPosition()
706 // Loaded model pivot is not the model center.
707 mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
708 mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
711 void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
718 GetImplementation(node).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
719 uint32_t childrenCount = node.GetChildCount();
720 for(uint32_t i = 0; i < childrenCount; ++i)
722 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
727 UpdateImageBasedLightTextureRecursively(childNode, diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
731 void Model::UpdateImageBasedLightScaleFactorRecursively(Scene3D::ModelNode node, float iblScaleFactor)
738 GetImplementation(node).SetImageBasedLightScaleFactor(iblScaleFactor);
740 uint32_t childrenCount = node.GetChildCount();
741 for(uint32_t i = 0; i < childrenCount; ++i)
743 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
748 UpdateImageBasedLightScaleFactorRecursively(childNode, iblScaleFactor);
752 void Model::UpdateImageBasedLightTexture()
754 Dali::Texture currentDiffuseTexture = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture;
755 Dali::Texture currentSpecularTexture = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture;
756 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
757 uint32_t currentIblSpecularMipmapLevels = (mDiffuseTexture && mSpecularTexture) ? mSpecularMipmapLevels : mSceneSpecularMipmapLevels;
759 if(!currentDiffuseTexture || !currentSpecularTexture)
761 currentDiffuseTexture = mDefaultDiffuseTexture;
762 currentSpecularTexture = mDefaultSpecularTexture;
763 currentIblScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
764 currentIblSpecularMipmapLevels = 1u;
767 UpdateImageBasedLightTextureRecursively(mModelRoot, currentDiffuseTexture, currentSpecularTexture, currentIblScaleFactor, currentIblSpecularMipmapLevels);
770 void Model::UpdateImageBasedLightScaleFactor()
772 if((!mDiffuseTexture || !mSpecularTexture) &&
773 (!mSceneDiffuseTexture || !mSceneSpecularTexture))
778 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
779 UpdateImageBasedLightScaleFactorRecursively(mModelRoot, currentIblScaleFactor);
782 void Model::ApplyCameraTransform(Dali::CameraActor camera) const
784 Vector3 selfPosition = Self().GetProperty<Vector3>(Actor::Property::POSITION);
785 Quaternion selfOrientation = Self().GetProperty<Quaternion>(Actor::Property::ORIENTATION);
786 Vector3 selfScale = Self().GetProperty<Vector3>(Actor::Property::SCALE);
788 Vector3 cameraPosition = camera.GetProperty<Vector3>(Actor::Property::POSITION);
789 Quaternion cameraOrientation = camera.GetProperty<Quaternion>(Actor::Property::ORIENTATION);
790 Vector3 cameraScale = camera.GetProperty<Vector3>(Actor::Property::SCALE);
792 // Models in glTF and dli are defined as right hand coordinate system.
793 // DALi uses left hand coordinate system. Scaling negative is for change winding order.
794 if(!Dali::Equals(Y_DIRECTION.Dot(Vector3::YAXIS), 1.0f))
796 // Reflect by XZ plane
797 cameraPosition.y = -cameraPosition.y;
798 Quaternion yDirectionQuaternion;
799 yDirectionQuaternion.mVector = Vector3::YAXIS;
800 // Reflect orientation
801 cameraOrientation = yDirectionQuaternion * cameraOrientation * yDirectionQuaternion;
804 Vector3 resultPosition;
805 Quaternion resultOrientation;
808 Matrix selfMatrix(false);
809 Matrix cameraMatrix(false);
810 Matrix resultMatrix(false);
811 selfMatrix.SetTransformComponents(selfScale, selfOrientation, selfPosition);
812 cameraMatrix.SetTransformComponents(cameraScale, cameraOrientation, cameraPosition);
813 Matrix::Multiply(resultMatrix, cameraMatrix, selfMatrix);
814 resultMatrix.GetTransformComponents(resultPosition, resultOrientation, resultScale);
816 camera.SetProperty(Actor::Property::POSITION, resultPosition);
817 camera.SetProperty(Actor::Property::ORIENTATION, resultOrientation);
818 camera.SetProperty(Actor::Property::SCALE, resultScale);
821 void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels)
823 if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
825 mSceneDiffuseTexture = diffuseTexture;
826 mSceneSpecularTexture = specularTexture;
827 mSceneIblScaleFactor = scaleFactor;
828 mSceneSpecularMipmapLevels = specularMipmapLevels;
829 // If Model IBL is not set, use SceneView's IBL.
830 if(!mDiffuseTexture || !mSpecularTexture)
832 UpdateImageBasedLightTexture();
837 void Model::NotifyImageBasedLightScaleFactor(float scaleFactor)
839 mSceneIblScaleFactor = scaleFactor;
840 if(mSceneDiffuseTexture && mSceneSpecularTexture)
842 UpdateImageBasedLightScaleFactor();
846 void Model::NotifyLightAdded(uint32_t lightIndex, Scene3D::Light light)
848 mLights[lightIndex] = light;
849 AddLightRecursively(mModelRoot, light, lightIndex);
852 void Model::NotifyLightRemoved(uint32_t lightIndex)
854 if(mLights[lightIndex])
856 RemoveLightRecursively(mModelRoot, lightIndex);
857 mLights[lightIndex].Reset();
861 void Model::OnModelLoadComplete()
863 if(!mModelLoadTask->HasSucceeded())
865 ResetResourceTasks();
867 if(ModelCacheManager::Get() && !mModelUrl.empty())
869 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
881 auto& resources = mModelLoadTask->GetResources();
882 auto& scene = mModelLoadTask->GetScene();
883 CreateAnimations(scene);
884 ResetCameraParameters();
885 if(!resources.mEnvironmentMaps.empty())
887 mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse;
888 mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
891 uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
892 for(uint32_t i = 0; i < maxLightCount; ++i)
896 AddLightRecursively(mModelRoot, mLights[i], i);
900 UpdateImageBasedLightTexture();
901 UpdateImageBasedLightScaleFactor();
902 Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
904 mModelResourceReady = true;
905 NotifyResourceReady();
906 ResetResourceTask(mModelLoadTask);
909 void Model::OnIblDiffuseLoadComplete()
911 mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
912 ResetResourceTask(mIblDiffuseLoadTask);
913 mIblDiffuseResourceReady = true;
914 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
920 void Model::OnIblSpecularLoadComplete()
922 mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
923 mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
924 ResetResourceTask(mIblSpecularLoadTask);
925 mIblSpecularResourceReady = true;
926 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
932 void Model::OnIblLoadComplete()
934 UpdateImageBasedLightTexture();
935 NotifyResourceReady();
938 void Model::OnSizeNotification(Dali::PropertyNotification& source)
943 void Model::ResetResourceTasks()
945 if(!Dali::Adaptor::IsAvailable())
949 ResetResourceTask(mModelLoadTask);
950 ResetResourceTask(mIblDiffuseLoadTask);
951 ResetResourceTask(mIblSpecularLoadTask);
954 void Model::ResetResourceTask(IntrusivePtr<AsyncTask> asyncTask)
960 Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
964 void Model::NotifyResourceReady()
966 if(!IsResourceReady())
970 Control::SetResourceReady();
973 void Model::CreateModel()
976 auto& resources = mModelLoadTask->GetResources();
977 auto& scene = mModelLoadTask->GetScene();
978 auto& resourceChoices = mModelLoadTask->GetResourceChoices();
979 Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
980 Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, {}, {}, {}};
982 // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
983 resources.GenerateResources();
984 for(auto iRoot : scene.GetRoots())
986 if(auto modelNode = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
988 scene.ConfigureSkinningShaders(resources, modelNode, std::move(nodeParams.mSkinnables));
989 ConfigureBlendShapeShaders(resources, scene, modelNode, std::move(nodeParams.mBlendshapeRequests));
991 scene.ApplyConstraints(modelNode, std::move(nodeParams.mConstrainables));
993 mModelRoot.Add(modelNode);
996 AddModelTreeToAABB(AABB, scene, resourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
999 UpdateBlendShapeNodeMap();
1001 mNaturalSize = AABB.CalculateSize();
1002 mModelPivot = AABB.CalculatePivot();
1003 mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1004 Vector3 controlSize = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
1005 if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y))
1007 Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1013 void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
1015 mAnimations.clear();
1016 if(!mModelLoadTask->GetAnimations().empty())
1018 auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
1019 if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
1021 return mModelRoot.FindChildByName(property.mNodeName);
1023 auto* node = scene.GetNode(property.mNodeIndex);
1026 return Dali::Actor();
1028 return mModelRoot.FindChildById(node->mNodeId);
1031 for(auto&& animation : mModelLoadTask->GetAnimations())
1033 Dali::Animation anim = animation.ReAnimate(getActor);
1034 mAnimations.push_back({animation.GetName(), anim});
1039 void Model::ResetCameraParameters()
1041 mCameraParameters.clear();
1042 if(!mModelLoadTask->GetCameras().empty())
1044 // Copy camera parameters.
1045 std::copy(mModelLoadTask->GetCameras().begin(), mModelLoadTask->GetCameras().end(), std::back_inserter(mCameraParameters));
1049 void Model::UpdateBlendShapeNodeMap()
1051 // Remove privous node map
1052 mBlendShapeModelNodeMap.clear();
1054 UpdateBlendShapeNodeMapRecursively(mBlendShapeModelNodeMap, mModelRoot);
1057 } // namespace Internal
1058 } // namespace Scene3D