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/image-resource-loader.h>
35 #include <dali-scene3d/internal/common/model-cache-manager.h>
36 #include <dali-scene3d/internal/controls/scene-view/scene-view-impl.h>
37 #include <dali-scene3d/internal/light/light-impl.h>
38 #include <dali-scene3d/internal/model-components/model-node-impl.h>
39 #include <dali-scene3d/public-api/controls/model/model.h>
40 #include <dali-scene3d/public-api/loader/animation-definition.h>
41 #include <dali-scene3d/public-api/loader/camera-parameters.h>
42 #include <dali-scene3d/public-api/loader/light-parameters.h>
43 #include <dali-scene3d/public-api/loader/load-result.h>
44 #include <dali-scene3d/public-api/loader/node-definition.h>
45 #include <dali-scene3d/public-api/loader/scene-definition.h>
46 #include <dali-scene3d/public-api/loader/shader-manager.h>
47 #include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
60 * Creates control through type registry
64 return Scene3D::Model::New(std::string());
67 // Setup properties, signals and actions using the type-registry.
68 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Model, Toolkit::Control, Create);
69 DALI_TYPE_REGISTRATION_END()
71 static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f);
72 static constexpr float SIZE_STEP_CONDITION = 0.1f;
74 static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false;
75 static constexpr bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false;
81 pointMin = Vector3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
82 pointMax = Vector3(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
85 void ConsiderNewPointInVolume(const Vector3& position)
87 pointMin.x = std::min(position.x, pointMin.x);
88 pointMin.y = std::min(position.y, pointMin.y);
89 pointMin.z = std::min(position.z, pointMin.z);
91 pointMax.x = std::max(position.x, pointMax.x);
92 pointMax.y = std::max(position.y, pointMax.y);
93 pointMax.z = std::max(position.z, pointMax.z);
96 Vector3 CalculateSize()
98 return pointMax - pointMin;
101 Vector3 CalculatePivot()
103 Vector3 pivot = pointMin / (pointMin - pointMax);
104 for(uint32_t i = 0; i < 3; ++i)
106 // To avoid divid by zero
107 if(Dali::Equals(pointMin[i], pointMax[i]))
119 void ConfigureBlendShapeShaders(
120 Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
122 std::vector<std::string> errors;
123 auto onError = [&errors](const std::string& msg) { errors.push_back(msg); };
124 if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
126 Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
127 for(auto& msg : errors)
129 flinger << msg << '\n';
134 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)
136 static constexpr uint32_t BOX_POINT_COUNT = 8;
137 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}};
140 const Dali::Scene3D::Loader::NodeDefinition* node = scene.GetNode(iNode);
141 Matrix localMatrix = node->GetLocalSpace();
142 Matrix::Multiply(nodeMatrix, localMatrix, parentMatrix);
145 if(node->GetExtents(nodeParams.mResources, volume[0], volume[1]))
147 for(uint32_t i = 0; i < BOX_POINT_COUNT; ++i)
149 Vector4 position = Vector4(volume[BBIndex[i][0]].x, volume[BBIndex[i][1]].y, volume[BBIndex[i][2]].z, 1.0f);
150 Vector4 objectPosition = nodeMatrix * position;
151 objectPosition /= objectPosition.w;
153 AABB.ConsiderNewPointInVolume(Vector3(objectPosition));
157 if(node->mCustomization)
159 if(!node->mChildren.empty())
161 auto choice = choices.Get(node->mCustomization->mTag);
162 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));
164 AddModelTreeToAABB(AABB, scene, choices, node->mChildren[i], nodeParams, nodeMatrix);
169 for(auto i : node->mChildren)
171 AddModelTreeToAABB(AABB, scene, choices, i, nodeParams, nodeMatrix);
176 void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node)
182 const auto childCount = node.GetChildCount();
183 for(auto i = 0u; i < childCount; ++i)
185 UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i)));
188 std::vector<std::string> blendShapeNames;
189 node.RetrieveBlendShapeNames(blendShapeNames);
190 for(const auto& iter : blendShapeNames)
192 // Append or create new list.
193 resultMap[iter].push_back(node);
197 void UpdateShaderRecursively(Scene3D::ModelNode node, Scene3D::Loader::ShaderManagerPtr shaderManager)
204 GetImplementation(node).UpdateShader(shaderManager);
206 uint32_t childrenCount = node.GetChildCount();
207 for(uint32_t i = 0; i < childrenCount; ++i)
209 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
212 UpdateShaderRecursively(childNode, shaderManager);
217 void UpdateShadowMapTextureRecursively(Scene3D::ModelNode node, Dali::Texture shadowMapTexture)
224 GetImplementation(node).SetShadowMapTexture(shadowMapTexture);
226 uint32_t childrenCount = node.GetChildCount();
227 for(uint32_t i = 0; i < childrenCount; ++i)
229 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
232 UpdateShadowMapTextureRecursively(childNode, shadowMapTexture);
237 } // anonymous namespace
239 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
240 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
242 mResourceDirectoryUrl(resourceDirectoryUrl),
244 mShaderManager(new Scene3D::Loader::ShaderManager()),
245 mNaturalSize(Vector3::ZERO),
246 mModelPivot(AnchorPoint::CENTER),
247 mSceneIblScaleFactor(1.0f),
248 mIblScaleFactor(1.0f),
249 mSceneSpecularMipmapLevels(1u),
250 mSpecularMipmapLevels(1u),
251 mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE),
252 mModelChildrenFocusable(DEFAULT_MODEL_CHILDREN_FOCUSABLE),
253 mModelResourceReady(false),
254 mIblDiffuseResourceReady(true),
255 mIblSpecularResourceReady(true),
256 mIblDiffuseDirty(false),
257 mIblSpecularDirty(false)
263 ResetResourceTasks();
265 if(ModelCacheManager::Get() && !mModelUrl.empty())
267 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
271 Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
273 Model* impl = new Model(modelUrl, resourceDirectoryUrl);
275 Dali::Scene3D::Model handle = Dali::Scene3D::Model(*impl);
277 // Second-phase init of the implementation
278 // This can only be done after the CustomActor connection has been made...
284 const Scene3D::ModelNode Model::GetModelRoot() const
289 void Model::AddModelNode(Scene3D::ModelNode modelNode)
296 mModelRoot.Add(modelNode);
297 if(mModelUrl.empty())
299 mModelResourceReady = true;
302 UpdateShaderRecursively(modelNode, mShaderManager);
304 if(mShadowMapTexture)
306 UpdateShadowMapTextureRecursively(modelNode, mShadowMapTexture);
309 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
311 UpdateImageBasedLightTexture();
312 UpdateImageBasedLightScaleFactor();
315 if(Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
317 NotifyResourceReady();
321 void Model::RemoveModelNode(Scene3D::ModelNode modelNode)
325 UpdateShaderRecursively(modelNode, nullptr);
326 mModelRoot.Remove(modelNode);
330 void Model::SetChildrenSensitive(bool enable)
332 if(mModelChildrenSensitive != enable)
334 mModelChildrenSensitive = enable;
337 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
342 bool Model::GetChildrenSensitive() const
344 return mModelChildrenSensitive;
347 void Model::SetChildrenFocusable(bool enable)
349 if(mModelChildrenFocusable != enable)
351 mModelChildrenFocusable = enable;
354 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
355 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
360 bool Model::GetChildrenFocusable() const
362 return mModelChildrenFocusable;
365 void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
367 bool needIblReset = false;
368 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
369 if(mDiffuseIblUrl != diffuseUrl)
371 mDiffuseIblUrl = diffuseUrl;
372 if(mDiffuseIblUrl.empty())
378 mIblDiffuseDirty = true;
379 mIblDiffuseResourceReady = false;
383 if(mSpecularIblUrl != specularUrl)
385 mSpecularIblUrl = specularUrl;
386 if(mSpecularIblUrl.empty())
392 mIblSpecularDirty = true;
393 mIblSpecularResourceReady = false;
397 // If one or both of diffuse url and specular url are empty,
398 // we don't need to request to load texture.
401 ResetResourceTask(mIblDiffuseLoadTask);
402 ResetResourceTask(mIblSpecularLoadTask);
404 mIblDiffuseDirty = false;
405 mIblSpecularDirty = false;
406 mIblDiffuseResourceReady = true;
407 mIblSpecularResourceReady = true;
409 mDiffuseTexture.Reset();
410 mSpecularTexture.Reset();
411 UpdateImageBasedLightTexture();
415 if(isOnScene && mIblDiffuseDirty)
417 ResetResourceTask(mIblDiffuseLoadTask);
418 mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete));
419 Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
420 mIblDiffuseDirty = false;
423 if(isOnScene && mIblSpecularDirty)
425 ResetResourceTask(mIblSpecularLoadTask);
426 mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete));
427 Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
428 mIblSpecularDirty = false;
432 if(!Dali::Equals(mIblScaleFactor, scaleFactor))
434 mIblScaleFactor = scaleFactor;
435 UpdateImageBasedLightScaleFactor();
438 // If diffuse and specular textures are already loaded, emits resource ready signal here.
439 NotifyResourceReady();
442 void Model::SetImageBasedLightScaleFactor(float scaleFactor)
444 mIblScaleFactor = scaleFactor;
445 if(mDiffuseTexture && mSpecularTexture)
447 UpdateImageBasedLightScaleFactor();
451 float Model::GetImageBasedLightScaleFactor() const
453 return mIblScaleFactor;
456 uint32_t Model::GetAnimationCount() const
458 return mAnimations.size();
461 Dali::Animation Model::GetAnimation(uint32_t index) const
463 Dali::Animation animation;
464 if(mAnimations.size() > index)
466 animation = mAnimations[index].second;
471 Dali::Animation Model::GetAnimation(const std::string& name) const
473 Dali::Animation animation;
476 for(auto&& animationData : mAnimations)
478 if(animationData.first == name)
480 animation = animationData.second;
488 uint32_t Model::GetCameraCount() const
490 return mCameraParameters.size();
493 Dali::CameraActor Model::GenerateCamera(uint32_t index) const
495 Dali::CameraActor camera;
496 if(mCameraParameters.size() > index)
498 camera = Dali::CameraActor::New3DCamera();
499 if(!mCameraParameters[index].ConfigureCamera(camera, false))
501 DALI_LOG_ERROR("Fail to generate %u's camera actor : Some property was not defined. Please check model file.\n", index);
506 ApplyCameraTransform(camera);
511 bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const
513 if(camera && mCameraParameters.size() > index)
515 if(!mCameraParameters[index].ConfigureCamera(camera, false))
517 DALI_LOG_ERROR("Fail to apply %u's camera actor : Some property was not defined. Please check model file.\n", index);
521 ApplyCameraTransform(camera);
527 Scene3D::ModelNode Model::FindChildModelNodeByName(std::string_view nodeName)
529 Actor childActor = Self().FindChildByName(nodeName);
530 return Scene3D::ModelNode::DownCast(childActor);
533 void Model::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
535 blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeModelNodeMap.size());
536 for(const auto& iter : mBlendShapeModelNodeMap)
538 blendShapeNames.push_back(iter.first);
542 void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<Scene3D::ModelNode>& modelNodes) const
544 auto iter = mBlendShapeModelNodeMap.find(std::string(blendShapeName));
545 if(iter != mBlendShapeModelNodeMap.end())
547 const auto& modelNodeList = iter->second;
548 modelNodes.reserve(modelNodes.size() + modelNodeList.size());
549 for(const auto& nodeIter : modelNodeList)
551 modelNodes.push_back(nodeIter);
556 Dali::Animation Model::GenerateMotionDataAnimation(Scene3D::MotionData motionData)
558 Dali::Animation animation;
560 // TODO : Need to collect duplicated codes with SetMotionData()
564 const uint32_t motionCount = motionData.GetMotionCount();
565 for(uint32_t i = 0u; i < motionCount; ++i)
567 auto motionIndex = motionData.GetIndex(i);
568 auto motionValue = motionData.GetValue(i);
569 if(motionIndex && motionValue)
571 if(motionIndex.GetModelNodeId() != Property::INVALID_KEY)
573 Scene3D::ModelNode modelNode;
574 if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING)
576 modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey);
578 else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX)
580 // TODO : Not implement yet.
585 KeyFrames keyFrames = motionValue.GetKeyFrames();
589 // Try to use index first. If failed, try to use name
590 Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode);
591 if(animatedPropertyIndex != Property::INVALID_INDEX)
593 if(DALI_UNLIKELY(!animation))
595 animation = Animation::New(motionData.GetDuration());
597 animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames);
601 std::string animatedPropertyName = motionIndex.GetPropertyName(modelNode);
602 Dali::Property property(modelNode, animatedPropertyName);
603 if(property.propertyIndex != Property::INVALID_INDEX)
605 if(DALI_UNLIKELY(!animation))
607 animation = Animation::New(motionData.GetDuration());
609 animation.AnimateBetween(property, keyFrames);
617 Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex);
618 if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING)
620 // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId,
621 // we need to animate all kind of blendshapes
623 KeyFrames keyFrames = motionValue.GetKeyFrames();
627 std::vector<Scene3D::ModelNode> modelNodes;
628 RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes);
630 for(auto& modelNode : modelNodes)
632 // Try to use index first. If failed, try to use name
633 Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode);
634 if(animatedPropertyIndex != Property::INVALID_INDEX)
636 if(DALI_UNLIKELY(!animation))
638 animation = Animation::New(motionData.GetDuration());
640 animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames);
644 std::string animatedPropertyName = motionIndex.GetPropertyName(modelNode);
645 Dali::Property property(modelNode, animatedPropertyName);
647 if(property.propertyIndex != Property::INVALID_INDEX)
649 if(DALI_UNLIKELY(!animation))
651 animation = Animation::New(motionData.GetDuration());
653 animation.AnimateBetween(property, keyFrames);
667 void Model::SetMotionData(Scene3D::MotionData motionData)
669 // TODO : Need to collect duplicated codes with GenerateMotionDataAnimation()
673 const uint32_t motionCount = motionData.GetMotionCount();
674 for(uint32_t i = 0u; i < motionCount; ++i)
676 auto motionIndex = motionData.GetIndex(i);
677 auto motionValue = motionData.GetValue(i);
678 if(motionIndex && motionValue)
680 if(motionIndex.GetModelNodeId() != Property::INVALID_KEY)
682 Scene3D::ModelNode modelNode;
683 if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING)
685 modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey);
687 else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX)
689 // TODO : Not implement yet.
694 Property::Value value = motionValue.GetPropertyValue();
696 if(value.GetType() != Property::Type::NONE)
698 // Try to use index first. If failed, try to use name
699 Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode);
700 if(propertyIndex != Property::INVALID_INDEX)
702 modelNode.SetProperty(propertyIndex, value);
706 std::string propertyName = motionIndex.GetPropertyName(modelNode);
707 Dali::Property property(modelNode, propertyName);
708 if(property.propertyIndex != Property::INVALID_INDEX)
710 modelNode.SetProperty(property.propertyIndex, value);
718 Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex);
719 if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING)
721 // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId,
722 // we need to animate all kind of blendshapes
724 Property::Value value = motionValue.GetPropertyValue();
726 if(value.GetType() != Property::Type::NONE)
728 std::vector<Scene3D::ModelNode> modelNodes;
729 RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes);
731 for(auto& modelNode : modelNodes)
733 // Try to use index first. If failed, try to use name
734 Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode);
735 if(propertyIndex != Property::INVALID_INDEX)
737 modelNode.SetProperty(propertyIndex, value);
741 std::string propertyName = motionIndex.GetPropertyName(modelNode);
742 Dali::Property property(modelNode, propertyName);
743 if(property.propertyIndex != Property::INVALID_INDEX)
745 modelNode.SetProperty(property.propertyIndex, value);
757 ///////////////////////////////////////////////////////////
762 void Model::OnInitialize()
764 // Make ParentOrigin as Center.
765 Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
767 mDefaultDiffuseTexture = ImageResourceLoader::GetEmptyTextureWhiteRGB();
768 mDefaultSpecularTexture = ImageResourceLoader::GetEmptyTextureWhiteRGB();
771 void Model::OnSceneConnection(int depth)
773 Actor parent = Self().GetParent();
776 // If this Model has parent SceneView and the its ShaderManager is same with privious ShaderManager,
777 // this Model don't need to update shader.
778 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
781 mParentSceneView = sceneView;
782 GetImpl(sceneView).RegisterSceneItem(this);
783 Scene3D::Loader::ShaderManagerPtr shaderManager = GetImpl(sceneView).GetShaderManager();
784 if(mShaderManager != shaderManager)
786 mShaderManager = shaderManager;
787 UpdateShaderRecursively(mModelRoot, mShaderManager);
791 parent = parent.GetParent();
794 // Model can be added on Dali::Scene directly without SceneView.
795 // So, Model's mShaderManager and shaders of child ModelNodes are needed to be reset when this Model has not parent SceneView.
796 Scene3D::SceneView parentSceneView = mParentSceneView.GetHandle();
799 mShaderManager = new Dali::Scene3D::Loader::ShaderManager();
800 UpdateShaderRecursively(mModelRoot, mShaderManager);
803 if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty())
805 // Request model load only if we setup url.
806 if(ModelCacheManager::Get())
808 ModelCacheManager::Get().ReferenceModelCache(mModelUrl);
810 mModelLoadTask = new ModelLoadTask(mModelUrl, mResourceDirectoryUrl, MakeCallback(this, &Model::OnModelLoadComplete));
811 Dali::AsyncTaskManager::Get().AddTask(mModelLoadTask);
814 // If diffuse and specular url is not valid, IBL does not need to be loaded.
815 if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
817 SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
820 NotifyResourceReady();
822 mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION));
823 mSizeNotification.NotifySignal().Connect(this, &Model::OnSizeNotification);
824 Control::OnSceneConnection(depth);
827 void Model::OnSceneDisconnection()
829 // If mParentSceneView is still onScene, that means this model
830 // is disconnected from mParentSceneView's sub tree.
831 // So, Unregister this Model from SceneView.
832 Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
833 if(sceneView && sceneView.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
835 GetImpl(sceneView).UnregisterSceneItem(this);
836 mParentSceneView.Reset();
839 mSizeNotification.NotifySignal().Disconnect(this, &Model::OnSizeNotification);
840 Self().RemovePropertyNotification(mSizeNotification);
841 mSizeNotification.Reset();
843 Control::OnSceneDisconnection();
846 void Model::OnSizeSet(const Vector3& size)
851 Vector3 Model::GetNaturalSize()
855 DALI_LOG_ERROR("Model is still not loaded.\n");
856 return Vector3::ZERO;
862 float Model::GetHeightForWidth(float width)
865 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
866 return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
869 float Model::GetWidthForHeight(float height)
872 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
873 return Control::GetWidthForHeight(height) + padding.start + padding.end;
876 void Model::OnRelayout(const Vector2& size, RelayoutContainer& container)
878 Control::OnRelayout(size, container);
882 bool Model::IsResourceReady() const
884 return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady;
887 void Model::CreateModelRoot()
889 mModelRoot = Scene3D::ModelNode::New();
890 mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
891 mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION);
892 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
893 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
894 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
895 Self().Add(mModelRoot);
898 void Model::ScaleModel(bool useCurrentSize)
906 Vector3 size = (useCurrentSize) ? Self().GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE) : Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
907 if(size.x > 0.0f && size.y > 0.0f)
910 scale = std::min(size.x / mNaturalSize.x, scale);
911 scale = std::min(size.y / mNaturalSize.y, scale);
913 // Models in glTF and dli are defined as right hand coordinate system.
914 // DALi uses left hand coordinate system. Scaling negative is for change winding order.
915 mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale);
918 void Model::FitModelPosition()
924 // Loaded model pivot is not the model center.
925 mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
926 mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
929 void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
936 GetImplementation(node).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
937 uint32_t childrenCount = node.GetChildCount();
938 for(uint32_t i = 0; i < childrenCount; ++i)
940 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
945 UpdateImageBasedLightTextureRecursively(childNode, diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
949 void Model::UpdateImageBasedLightScaleFactorRecursively(Scene3D::ModelNode node, float iblScaleFactor)
956 GetImplementation(node).SetImageBasedLightScaleFactor(iblScaleFactor);
958 uint32_t childrenCount = node.GetChildCount();
959 for(uint32_t i = 0; i < childrenCount; ++i)
961 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
966 UpdateImageBasedLightScaleFactorRecursively(childNode, iblScaleFactor);
970 void Model::UpdateImageBasedLightTexture()
972 Dali::Texture currentDiffuseTexture = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture;
973 Dali::Texture currentSpecularTexture = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture;
974 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
975 uint32_t currentIblSpecularMipmapLevels = (mDiffuseTexture && mSpecularTexture) ? mSpecularMipmapLevels : mSceneSpecularMipmapLevels;
977 if(!currentDiffuseTexture || !currentSpecularTexture)
979 currentDiffuseTexture = mDefaultDiffuseTexture;
980 currentSpecularTexture = mDefaultSpecularTexture;
981 currentIblScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
982 currentIblSpecularMipmapLevels = 1u;
985 UpdateImageBasedLightTextureRecursively(mModelRoot, currentDiffuseTexture, currentSpecularTexture, currentIblScaleFactor, currentIblSpecularMipmapLevels);
988 void Model::UpdateImageBasedLightScaleFactor()
990 if((!mDiffuseTexture || !mSpecularTexture) &&
991 (!mSceneDiffuseTexture || !mSceneSpecularTexture))
996 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
997 UpdateImageBasedLightScaleFactorRecursively(mModelRoot, currentIblScaleFactor);
1000 void Model::ApplyCameraTransform(Dali::CameraActor camera) const
1002 Vector3 selfPosition = Self().GetProperty<Vector3>(Actor::Property::POSITION);
1003 Quaternion selfOrientation = Self().GetProperty<Quaternion>(Actor::Property::ORIENTATION);
1004 Vector3 selfScale = Self().GetProperty<Vector3>(Actor::Property::SCALE);
1006 Vector3 cameraPosition = camera.GetProperty<Vector3>(Actor::Property::POSITION);
1007 Quaternion cameraOrientation = camera.GetProperty<Quaternion>(Actor::Property::ORIENTATION);
1008 Vector3 cameraScale = camera.GetProperty<Vector3>(Actor::Property::SCALE);
1010 // Models in glTF and dli are defined as right hand coordinate system.
1011 // DALi uses left hand coordinate system. Scaling negative is for change winding order.
1012 if(!Dali::Equals(Y_DIRECTION.Dot(Vector3::YAXIS), 1.0f))
1014 // Reflect by XZ plane
1015 cameraPosition.y = -cameraPosition.y;
1016 Quaternion yDirectionQuaternion;
1017 yDirectionQuaternion.mVector = Vector3::YAXIS;
1018 // Reflect orientation
1019 cameraOrientation = yDirectionQuaternion * cameraOrientation * yDirectionQuaternion;
1022 Vector3 resultPosition;
1023 Quaternion resultOrientation;
1024 Vector3 resultScale;
1026 Matrix selfMatrix(false);
1027 Matrix cameraMatrix(false);
1028 Matrix resultMatrix(false);
1029 selfMatrix.SetTransformComponents(selfScale, selfOrientation, selfPosition);
1030 cameraMatrix.SetTransformComponents(cameraScale, cameraOrientation, cameraPosition);
1031 Matrix::Multiply(resultMatrix, cameraMatrix, selfMatrix);
1032 resultMatrix.GetTransformComponents(resultPosition, resultOrientation, resultScale);
1034 camera.SetProperty(Actor::Property::POSITION, resultPosition);
1035 camera.SetProperty(Actor::Property::ORIENTATION, resultOrientation);
1036 camera.SetProperty(Actor::Property::SCALE, resultScale);
1039 void Model::NotifyShadowMapTexture(Dali::Texture shadowMapTexture)
1041 if(mShadowMapTexture != shadowMapTexture)
1043 mShadowMapTexture = shadowMapTexture;
1044 UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture);
1048 void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels)
1050 if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
1052 mSceneDiffuseTexture = diffuseTexture;
1053 mSceneSpecularTexture = specularTexture;
1054 mSceneIblScaleFactor = scaleFactor;
1055 mSceneSpecularMipmapLevels = specularMipmapLevels;
1056 // If Model IBL is not set, use SceneView's IBL.
1057 if(!mDiffuseTexture || !mSpecularTexture)
1059 UpdateImageBasedLightTexture();
1064 void Model::NotifyImageBasedLightScaleFactor(float scaleFactor)
1066 mSceneIblScaleFactor = scaleFactor;
1067 if(mSceneDiffuseTexture && mSceneSpecularTexture)
1069 UpdateImageBasedLightScaleFactor();
1073 void Model::OnModelLoadComplete()
1075 IntrusivePtr<Model> self = this; // Keep reference until this API finished
1077 if(!mModelLoadTask->HasSucceeded())
1079 ResetResourceTasks();
1081 if(ModelCacheManager::Get() && !mModelUrl.empty())
1083 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
1095 auto& resources = mModelLoadTask->GetResources();
1096 auto& scene = mModelLoadTask->GetScene();
1097 CreateAnimations(scene);
1098 ResetCameraParameters();
1099 if(!resources.mEnvironmentMaps.empty())
1101 if(resources.mEnvironmentMaps.front().second.mDiffuse)
1103 mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse;
1105 if(resources.mEnvironmentMaps.front().second.mSpecular)
1107 mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
1111 if(mShadowMapTexture)
1113 UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture);
1115 UpdateImageBasedLightTexture();
1116 UpdateImageBasedLightScaleFactor();
1117 Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
1119 mModelResourceReady = true;
1120 ResetResourceTask(mModelLoadTask);
1121 NotifyResourceReady();
1124 void Model::OnIblDiffuseLoadComplete()
1126 mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
1127 ResetResourceTask(mIblDiffuseLoadTask);
1128 mIblDiffuseResourceReady = true;
1129 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1131 OnIblLoadComplete();
1135 void Model::OnIblSpecularLoadComplete()
1137 mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
1138 mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
1139 ResetResourceTask(mIblSpecularLoadTask);
1140 mIblSpecularResourceReady = true;
1141 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1143 OnIblLoadComplete();
1147 void Model::OnIblLoadComplete()
1149 UpdateImageBasedLightTexture();
1150 NotifyResourceReady();
1153 void Model::OnSizeNotification(Dali::PropertyNotification& source)
1158 void Model::ResetResourceTasks()
1160 if(!Dali::Adaptor::IsAvailable())
1164 ResetResourceTask(mModelLoadTask);
1165 ResetResourceTask(mIblDiffuseLoadTask);
1166 ResetResourceTask(mIblSpecularLoadTask);
1169 void Model::ResetResourceTask(IntrusivePtr<AsyncTask> asyncTask)
1175 Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
1179 void Model::NotifyResourceReady()
1181 if(!IsResourceReady())
1185 Control::SetResourceReady();
1188 void Model::CreateModel()
1190 BoundingVolume AABB;
1191 auto& resources = mModelLoadTask->GetResources();
1192 auto& scene = mModelLoadTask->GetScene();
1193 auto& resourceChoices = mModelLoadTask->GetResourceChoices();
1194 Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
1196 Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, mShaderManager, {}, {}, {}};
1198 // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
1199 resources.GenerateResources();
1200 for(auto iRoot : scene.GetRoots())
1202 if(auto modelNode = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
1204 scene.ConfigureSkinningShaders(resources, modelNode, std::move(nodeParams.mSkinnables));
1205 ConfigureBlendShapeShaders(resources, scene, modelNode, std::move(nodeParams.mBlendshapeRequests));
1207 scene.ApplyConstraints(modelNode, std::move(nodeParams.mConstrainables));
1209 mModelRoot.Add(modelNode);
1212 AddModelTreeToAABB(AABB, scene, resourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
1215 UpdateBlendShapeNodeMap();
1217 mNaturalSize = AABB.CalculateSize();
1218 mModelPivot = AABB.CalculatePivot();
1219 mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1220 Vector3 controlSize = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
1221 if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y))
1223 Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1229 void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
1231 mAnimations.clear();
1232 if(!mModelLoadTask->GetAnimations().empty())
1234 auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
1235 if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
1237 return mModelRoot.FindChildByName(property.mNodeName);
1239 auto* node = scene.GetNode(property.mNodeIndex);
1242 return Dali::Actor();
1244 return mModelRoot.FindChildById(node->mNodeId);
1247 for(auto&& animation : mModelLoadTask->GetAnimations())
1249 Dali::Animation anim = animation.ReAnimate(getActor);
1250 mAnimations.push_back({animation.GetName(), anim});
1255 void Model::ResetCameraParameters()
1257 mCameraParameters.clear();
1258 if(!mModelLoadTask->GetCameras().empty())
1260 // Copy camera parameters.
1261 std::copy(mModelLoadTask->GetCameras().begin(), mModelLoadTask->GetCameras().end(), std::back_inserter(mCameraParameters));
1265 void Model::UpdateBlendShapeNodeMap()
1267 // Remove privous node map
1268 mBlendShapeModelNodeMap.clear();
1270 UpdateBlendShapeNodeMapRecursively(mBlendShapeModelNodeMap, mModelRoot);
1273 } // namespace Internal
1274 } // namespace Scene3D