2 * Copyright (c) 2024 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/event/collider-mesh-processor.h>
38 #include <dali-scene3d/internal/light/light-impl.h>
39 #include <dali-scene3d/internal/model-components/model-node-impl.h>
40 #include <dali-scene3d/public-api/controls/model/model.h>
41 #include <dali-scene3d/public-api/loader/animation-definition.h>
42 #include <dali-scene3d/public-api/loader/camera-parameters.h>
43 #include <dali-scene3d/public-api/loader/light-parameters.h>
44 #include <dali-scene3d/public-api/loader/load-result.h>
45 #include <dali-scene3d/public-api/loader/node-definition.h>
46 #include <dali-scene3d/public-api/loader/scene-definition.h>
47 #include <dali-scene3d/public-api/loader/shader-manager.h>
48 #include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
49 #include <dali-toolkit/public-api/controls/control-impl.h>
61 * Creates control through type registry
65 return Scene3D::Model::New(std::string());
68 // Setup properties, signals and actions using the type-registry.
69 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Model, Toolkit::Control, Create);
70 DALI_TYPE_REGISTRATION_END()
72 static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f);
73 static constexpr float SIZE_STEP_CONDITION = 0.1f;
75 static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false;
76 static constexpr bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false;
82 pointMin = Vector3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
83 pointMax = Vector3(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
86 void ConsiderNewPointInVolume(const Vector3& position)
88 pointMin.x = std::min(position.x, pointMin.x);
89 pointMin.y = std::min(position.y, pointMin.y);
90 pointMin.z = std::min(position.z, pointMin.z);
92 pointMax.x = std::max(position.x, pointMax.x);
93 pointMax.y = std::max(position.y, pointMax.y);
94 pointMax.z = std::max(position.z, pointMax.z);
97 Vector3 CalculateSize()
99 return pointMax - pointMin;
102 Vector3 CalculatePivot()
104 Vector3 pivot = pointMin / (pointMin - pointMax);
105 for(uint32_t i = 0; i < 3; ++i)
107 // To avoid divid by zero
108 if(Dali::Equals(pointMin[i], pointMax[i]))
120 void ConfigureBlendShapeShaders(
121 Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
123 std::vector<std::string> errors;
124 auto onError = [&errors](const std::string& msg) { errors.push_back(msg); };
125 if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
127 Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
128 for(auto& msg : errors)
130 flinger << msg << '\n';
135 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)
137 static constexpr uint32_t BOX_POINT_COUNT = 8;
138 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}};
141 const Dali::Scene3D::Loader::NodeDefinition* node = scene.GetNode(iNode);
142 Matrix localMatrix = node->GetLocalSpace();
143 Matrix::Multiply(nodeMatrix, localMatrix, parentMatrix);
146 if(node->GetExtents(nodeParams.mResources, volume[0], volume[1]))
148 for(uint32_t i = 0; i < BOX_POINT_COUNT; ++i)
150 Vector4 position = Vector4(volume[BBIndex[i][0]].x, volume[BBIndex[i][1]].y, volume[BBIndex[i][2]].z, 1.0f);
151 Vector4 objectPosition = nodeMatrix * position;
152 objectPosition /= objectPosition.w;
154 AABB.ConsiderNewPointInVolume(Vector3(objectPosition));
158 if(node->mCustomization)
160 if(!node->mChildren.empty())
162 auto choice = choices.Get(node->mCustomization->mTag);
163 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));
165 AddModelTreeToAABB(AABB, scene, choices, node->mChildren[i], nodeParams, nodeMatrix);
170 for(auto i : node->mChildren)
172 AddModelTreeToAABB(AABB, scene, choices, i, nodeParams, nodeMatrix);
177 void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node)
183 const auto childCount = node.GetChildCount();
184 for(auto i = 0u; i < childCount; ++i)
186 UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i)));
189 std::vector<std::string> blendShapeNames;
190 node.RetrieveBlendShapeNames(blendShapeNames);
191 for(const auto& iter : blendShapeNames)
193 // Append or create new list.
194 resultMap[iter].push_back(node);
198 void UpdateShaderRecursively(Scene3D::ModelNode node, Scene3D::Loader::ShaderManagerPtr shaderManager)
205 GetImplementation(node).UpdateShader(shaderManager);
207 uint32_t childrenCount = node.GetChildCount();
208 for(uint32_t i = 0; i < childrenCount; ++i)
210 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
213 UpdateShaderRecursively(childNode, shaderManager);
218 void UpdateShadowMapTextureRecursively(Scene3D::ModelNode node, Dali::Texture shadowMapTexture)
225 GetImplementation(node).SetShadowMapTexture(shadowMapTexture);
227 uint32_t childrenCount = node.GetChildCount();
228 for(uint32_t i = 0; i < childrenCount; ++i)
230 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
233 UpdateShadowMapTextureRecursively(childNode, shadowMapTexture);
238 void ResetResourceTask(IntrusivePtr<AsyncTask>&& asyncTask)
244 Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
248 } // anonymous namespace
250 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
251 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
253 mResourceDirectoryUrl(resourceDirectoryUrl),
255 mShaderManager(new Scene3D::Loader::ShaderManager()),
256 mNaturalSize(Vector3::ZERO),
257 mModelPivot(AnchorPoint::CENTER),
258 mSceneIblScaleFactor(1.0f),
259 mIblScaleFactor(1.0f),
260 mSceneSpecularMipmapLevels(1u),
261 mSpecularMipmapLevels(1u),
262 mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE),
263 mModelChildrenFocusable(DEFAULT_MODEL_CHILDREN_FOCUSABLE),
264 mModelResourceReady(false),
265 mIblDiffuseResourceReady(true),
266 mIblSpecularResourceReady(true),
267 mIblDiffuseDirty(false),
268 mIblSpecularDirty(false),
269 mIsShadowCasting(true),
270 mIsShadowReceiving(true)
276 ResetResourceTasks();
278 if(ModelCacheManager::Get() && !mModelUrl.empty())
280 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
284 Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
286 Model* impl = new Model(modelUrl, resourceDirectoryUrl);
288 Dali::Scene3D::Model handle = Dali::Scene3D::Model(*impl);
290 // Second-phase init of the implementation
291 // This can only be done after the CustomActor connection has been made...
297 const Scene3D::ModelNode Model::GetModelRoot() const
302 void Model::AddModelNode(Scene3D::ModelNode modelNode)
309 mModelRoot.Add(modelNode);
310 if(mModelUrl.empty())
312 mModelResourceReady = true;
315 UpdateShaderRecursively(modelNode, mShaderManager);
317 if(mShadowMapTexture)
319 UpdateShadowMapTextureRecursively(modelNode, mShadowMapTexture);
322 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
324 UpdateImageBasedLightTexture();
325 UpdateImageBasedLightScaleFactor();
328 GetImplementation(modelNode).SetRootModel(this);
330 // If model has a collider mesh set, add it to the container
331 if(modelNode.HasColliderMesh())
333 RegisterColliderMesh(modelNode);
334 Scene3D::ColliderMeshProcessor::Get().ColliderMeshChanged(Scene3D::Model::DownCast(Self()));
337 if(Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
339 NotifyResourceReady();
343 void Model::RegisterColliderMesh(Scene3D::ModelNode& modelNode)
345 mColliderMeshes[modelNode.GetProperty<int>(Actor::Property::ID)] = modelNode;
348 Scene3D::ColliderMeshProcessor::Get().ColliderMeshChanged(Scene3D::Model::DownCast(Self()));
351 void Model::RemoveColliderMesh(Scene3D::ModelNode& node)
353 auto id = node.GetProperty<int>(Actor::Property::ID);
354 auto iter = std::find_if(mColliderMeshes.begin(), mColliderMeshes.end(), [id](auto& item) {
355 return item.first == id;
357 if(iter != mColliderMeshes.end())
359 mColliderMeshes.erase(iter);
363 void Model::RemoveModelNode(Scene3D::ModelNode modelNode)
365 // remove collider mesh from the list if node is being removed
366 if(modelNode.HasColliderMesh())
368 RemoveColliderMesh(modelNode);
369 GetImplementation(modelNode).SetRootModel(nullptr);
374 UpdateShaderRecursively(modelNode, nullptr);
375 mModelRoot.Remove(modelNode);
379 void Model::SetChildrenSensitive(bool enable)
381 if(mModelChildrenSensitive != enable)
383 mModelChildrenSensitive = enable;
386 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
391 bool Model::GetChildrenSensitive() const
393 return mModelChildrenSensitive;
396 void Model::SetChildrenFocusable(bool enable)
398 if(mModelChildrenFocusable != enable)
400 mModelChildrenFocusable = enable;
403 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
404 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
409 bool Model::GetChildrenFocusable() const
411 return mModelChildrenFocusable;
414 void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
416 bool needIblReset = false;
417 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
418 if(mDiffuseIblUrl != diffuseUrl)
420 mDiffuseIblUrl = diffuseUrl;
421 if(mDiffuseIblUrl.empty())
427 mIblDiffuseDirty = true;
428 mIblDiffuseResourceReady = false;
432 if(mSpecularIblUrl != specularUrl)
434 mSpecularIblUrl = specularUrl;
435 if(mSpecularIblUrl.empty())
441 mIblSpecularDirty = true;
442 mIblSpecularResourceReady = false;
446 // If one or both of diffuse url and specular url are empty,
447 // we don't need to request to load texture.
450 ResetResourceTask(mIblDiffuseLoadTask);
451 ResetResourceTask(mIblSpecularLoadTask);
453 mIblDiffuseDirty = false;
454 mIblSpecularDirty = false;
455 mIblDiffuseResourceReady = true;
456 mIblSpecularResourceReady = true;
458 mDiffuseTexture.Reset();
459 mSpecularTexture.Reset();
460 UpdateImageBasedLightTexture();
462 // Request image resource GC
463 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
467 if(isOnScene && mIblDiffuseDirty)
469 ResetResourceTask(mIblDiffuseLoadTask);
470 mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete));
471 Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
472 mIblDiffuseDirty = false;
474 // Request image resource GC
475 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
478 if(isOnScene && mIblSpecularDirty)
480 ResetResourceTask(mIblSpecularLoadTask);
481 mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete));
482 Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
483 mIblSpecularDirty = false;
485 // Request image resource GC
486 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
490 if(!Dali::Equals(mIblScaleFactor, scaleFactor))
492 mIblScaleFactor = scaleFactor;
493 UpdateImageBasedLightScaleFactor();
496 // If diffuse and specular textures are already loaded, emits resource ready signal here.
497 NotifyResourceReady();
500 void Model::SetImageBasedLightScaleFactor(float scaleFactor)
502 mIblScaleFactor = scaleFactor;
503 if(mDiffuseTexture && mSpecularTexture)
505 UpdateImageBasedLightScaleFactor();
509 float Model::GetImageBasedLightScaleFactor() const
511 return mIblScaleFactor;
514 uint32_t Model::GetAnimationCount() const
516 return mAnimations.size();
519 Dali::Animation Model::GetAnimation(uint32_t index) const
521 Dali::Animation animation;
522 if(mAnimations.size() > index)
524 animation = mAnimations[index].second;
529 Dali::Animation Model::GetAnimation(const std::string& name) const
531 Dali::Animation animation;
534 for(auto&& animationData : mAnimations)
536 if(animationData.first == name)
538 animation = animationData.second;
546 uint32_t Model::GetCameraCount() const
548 return mCameraParameters.size();
551 Dali::CameraActor Model::GenerateCamera(uint32_t index) const
553 Dali::CameraActor camera;
554 if(mCameraParameters.size() > index)
556 camera = Dali::CameraActor::New3DCamera();
557 if(!mCameraParameters[index].ConfigureCamera(camera, false))
559 DALI_LOG_ERROR("Fail to generate %u's camera actor : Some property was not defined. Please check model file.\n", index);
564 ApplyCameraTransform(camera);
569 bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const
571 if(camera && mCameraParameters.size() > index)
573 if(!mCameraParameters[index].ConfigureCamera(camera, false))
575 DALI_LOG_ERROR("Fail to apply %u's camera actor : Some property was not defined. Please check model file.\n", index);
579 ApplyCameraTransform(camera);
585 Scene3D::ModelNode Model::FindChildModelNodeByName(std::string_view nodeName)
587 Actor childActor = Self().FindChildByName(nodeName);
588 return Scene3D::ModelNode::DownCast(childActor);
591 void Model::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
593 blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeModelNodeMap.size());
594 for(const auto& iter : mBlendShapeModelNodeMap)
596 blendShapeNames.push_back(iter.first);
600 void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<Scene3D::ModelNode>& modelNodes) const
602 auto iter = mBlendShapeModelNodeMap.find(std::string(blendShapeName));
603 if(iter != mBlendShapeModelNodeMap.end())
605 const auto& modelNodeList = iter->second;
606 modelNodes.reserve(modelNodes.size() + modelNodeList.size());
607 for(const auto& nodeIter : modelNodeList)
609 modelNodes.push_back(nodeIter);
614 Dali::Animation Model::GenerateMotionDataAnimation(Scene3D::MotionData motionData)
616 Dali::Animation animation;
618 // TODO : Need to collect duplicated codes with SetMotionData()
622 const uint32_t motionCount = motionData.GetMotionCount();
623 for(uint32_t i = 0u; i < motionCount; ++i)
625 auto motionIndex = motionData.GetIndex(i);
626 auto motionValue = motionData.GetValue(i);
627 if(motionIndex && motionValue)
629 if(motionIndex.GetModelNodeId() != Property::INVALID_KEY)
631 Scene3D::ModelNode modelNode;
632 if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING)
634 modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey);
636 else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX)
638 // TODO : Not implement yet.
643 KeyFrames keyFrames = motionValue.GetKeyFrames();
647 // Try to use index first. If failed, try to use name
648 Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode);
649 if(animatedPropertyIndex != Property::INVALID_INDEX)
651 if(DALI_UNLIKELY(!animation))
653 animation = Animation::New(motionData.GetDuration());
655 animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames);
659 std::string animatedPropertyName = motionIndex.GetPropertyName(modelNode);
660 Dali::Property property(modelNode, animatedPropertyName);
661 if(property.propertyIndex != Property::INVALID_INDEX)
663 if(DALI_UNLIKELY(!animation))
665 animation = Animation::New(motionData.GetDuration());
667 animation.AnimateBetween(property, keyFrames);
675 Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex);
676 if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING)
678 // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId,
679 // we need to animate all kind of blendshapes
681 KeyFrames keyFrames = motionValue.GetKeyFrames();
685 std::vector<Scene3D::ModelNode> modelNodes;
686 RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes);
688 for(auto& modelNode : modelNodes)
690 // Try to use index first. If failed, try to use name
691 Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode);
692 if(animatedPropertyIndex != Property::INVALID_INDEX)
694 if(DALI_UNLIKELY(!animation))
696 animation = Animation::New(motionData.GetDuration());
698 animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames);
702 std::string animatedPropertyName = motionIndex.GetPropertyName(modelNode);
703 Dali::Property property(modelNode, animatedPropertyName);
705 if(property.propertyIndex != Property::INVALID_INDEX)
707 if(DALI_UNLIKELY(!animation))
709 animation = Animation::New(motionData.GetDuration());
711 animation.AnimateBetween(property, keyFrames);
725 void Model::SetMotionData(Scene3D::MotionData motionData)
727 // TODO : Need to collect duplicated codes with GenerateMotionDataAnimation()
731 const uint32_t motionCount = motionData.GetMotionCount();
732 for(uint32_t i = 0u; i < motionCount; ++i)
734 auto motionIndex = motionData.GetIndex(i);
735 auto motionValue = motionData.GetValue(i);
736 if(motionIndex && motionValue)
738 if(motionIndex.GetModelNodeId() != Property::INVALID_KEY)
740 Scene3D::ModelNode modelNode;
741 if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING)
743 modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey);
745 else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX)
747 // TODO : Not implement yet.
752 Property::Value value = motionValue.GetPropertyValue();
754 if(value.GetType() != Property::Type::NONE)
756 // Try to use index first. If failed, try to use name
757 Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode);
758 if(propertyIndex != Property::INVALID_INDEX)
760 modelNode.SetProperty(propertyIndex, value);
764 std::string propertyName = motionIndex.GetPropertyName(modelNode);
765 Dali::Property property(modelNode, propertyName);
766 if(property.propertyIndex != Property::INVALID_INDEX)
768 modelNode.SetProperty(property.propertyIndex, value);
776 Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex);
777 if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING)
779 // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId,
780 // we need to animate all kind of blendshapes
782 Property::Value value = motionValue.GetPropertyValue();
784 if(value.GetType() != Property::Type::NONE)
786 std::vector<Scene3D::ModelNode> modelNodes;
787 RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes);
789 for(auto& modelNode : modelNodes)
791 // Try to use index first. If failed, try to use name
792 Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode);
793 if(propertyIndex != Property::INVALID_INDEX)
795 modelNode.SetProperty(propertyIndex, value);
799 std::string propertyName = motionIndex.GetPropertyName(modelNode);
800 Dali::Property property(modelNode, propertyName);
801 if(property.propertyIndex != Property::INVALID_INDEX)
803 modelNode.SetProperty(property.propertyIndex, value);
815 void Model::CastShadow(bool castShadow)
817 mIsShadowCasting = castShadow;
818 UpdateCastShadowRecursively(mModelRoot, mIsShadowCasting);
821 bool Model::IsShadowCasting() const
823 return mIsShadowCasting;
826 void Model::ReceiveShadow(bool receiveShadow)
828 mIsShadowReceiving = receiveShadow;
829 UpdateReceiveShadowRecursively(mModelRoot, mIsShadowReceiving);
832 bool Model::IsShadowReceiving() const
834 return mIsShadowReceiving;
838 ///////////////////////////////////////////////////////////
843 void Model::OnInitialize()
845 // Make ParentOrigin as Center.
846 Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
848 mDefaultDiffuseTexture = ImageResourceLoader::GetEmptyTextureWhiteRGB();
849 mDefaultSpecularTexture = ImageResourceLoader::GetEmptyTextureWhiteRGB();
852 void Model::OnSceneConnection(int depth)
854 Actor parent = Self().GetParent();
857 // If this Model has parent SceneView and the its ShaderManager is same with privious ShaderManager,
858 // this Model don't need to update shader.
859 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
862 mParentSceneView = sceneView;
863 GetImpl(sceneView).RegisterSceneItem(this);
864 Scene3D::Loader::ShaderManagerPtr shaderManager = GetImpl(sceneView).GetShaderManager();
865 if(mShaderManager != shaderManager)
867 mShaderManager = shaderManager;
868 UpdateShaderRecursively(mModelRoot, mShaderManager);
872 parent = parent.GetParent();
875 // Model can be added on Dali::Scene directly without SceneView.
876 // So, Model's mShaderManager and shaders of child ModelNodes are needed to be reset when this Model has not parent SceneView.
877 Scene3D::SceneView parentSceneView = mParentSceneView.GetHandle();
880 mShaderManager = new Dali::Scene3D::Loader::ShaderManager();
881 UpdateShaderRecursively(mModelRoot, mShaderManager);
884 if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty())
886 // Request model load only if we setup url.
887 if(ModelCacheManager::Get())
889 ModelCacheManager::Get().ReferenceModelCache(mModelUrl);
891 mModelLoadTask = new ModelLoadTask(mModelUrl, mResourceDirectoryUrl, MakeCallback(this, &Model::OnModelLoadComplete));
892 Dali::AsyncTaskManager::Get().AddTask(mModelLoadTask);
895 // If diffuse and specular url is not valid, IBL does not need to be loaded.
896 if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
898 SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
901 NotifyResourceReady();
903 mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION));
904 mSizeNotification.NotifySignal().Connect(this, &Model::OnSizeNotification);
905 Control::OnSceneConnection(depth);
908 void Model::OnSceneDisconnection()
910 // If mParentSceneView is still onScene, that means this model
911 // is disconnected from mParentSceneView's sub tree.
912 // So, Unregister this Model from SceneView.
913 Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
914 if(sceneView && sceneView.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
916 GetImpl(sceneView).UnregisterSceneItem(this);
917 mParentSceneView.Reset();
920 mSizeNotification.NotifySignal().Disconnect(this, &Model::OnSizeNotification);
921 Self().RemovePropertyNotification(mSizeNotification);
922 mSizeNotification.Reset();
924 Control::OnSceneDisconnection();
927 void Model::OnSizeSet(const Vector3& size)
932 Vector3 Model::GetNaturalSize()
936 DALI_LOG_ERROR("Model is still not loaded.\n");
937 return Vector3::ZERO;
943 float Model::GetHeightForWidth(float width)
946 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
947 return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
950 float Model::GetWidthForHeight(float height)
953 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
954 return Control::GetWidthForHeight(height) + padding.start + padding.end;
957 void Model::OnRelayout(const Vector2& size, RelayoutContainer& container)
959 Control::OnRelayout(size, container);
963 bool Model::IsResourceReady() const
965 return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady;
968 void Model::CreateModelRoot()
970 mModelRoot = Scene3D::ModelNode::New();
971 mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
972 mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION);
973 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
974 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
975 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
976 Self().Add(mModelRoot);
979 void Model::ScaleModel(bool useCurrentSize)
987 Vector3 size = (useCurrentSize) ? Self().GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE) : Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
988 if(size.x > 0.0f && size.y > 0.0f)
991 scale = std::min(size.x / mNaturalSize.x, scale);
992 scale = std::min(size.y / mNaturalSize.y, scale);
994 // Models in glTF and dli are defined as right hand coordinate system.
995 // DALi uses left hand coordinate system. Scaling negative is for change winding order.
996 mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale);
999 void Model::FitModelPosition()
1005 // Loaded model pivot is not the model center.
1006 mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
1007 mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
1010 void Model::UpdateCastShadowRecursively(Scene3D::ModelNode node, bool castShadow)
1017 GetImplementation(node).CastShadow(castShadow);
1018 uint32_t childrenCount = node.GetChildCount();
1019 for(uint32_t i = 0; i < childrenCount; ++i)
1021 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
1026 UpdateCastShadowRecursively(childNode, castShadow);
1030 void Model::UpdateReceiveShadowRecursively(Scene3D::ModelNode node, bool receiveShadow)
1037 GetImplementation(node).ReceiveShadow(receiveShadow);
1038 uint32_t childrenCount = node.GetChildCount();
1039 for(uint32_t i = 0; i < childrenCount; ++i)
1041 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
1046 UpdateReceiveShadowRecursively(childNode, receiveShadow);
1050 void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
1057 GetImplementation(node).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
1058 uint32_t childrenCount = node.GetChildCount();
1059 for(uint32_t i = 0; i < childrenCount; ++i)
1061 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
1066 UpdateImageBasedLightTextureRecursively(childNode, diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
1070 void Model::UpdateImageBasedLightScaleFactorRecursively(Scene3D::ModelNode node, float iblScaleFactor)
1077 GetImplementation(node).SetImageBasedLightScaleFactor(iblScaleFactor);
1079 uint32_t childrenCount = node.GetChildCount();
1080 for(uint32_t i = 0; i < childrenCount; ++i)
1082 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
1087 UpdateImageBasedLightScaleFactorRecursively(childNode, iblScaleFactor);
1091 void Model::UpdateImageBasedLightTexture()
1093 Dali::Texture currentDiffuseTexture = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture;
1094 Dali::Texture currentSpecularTexture = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture;
1095 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
1096 uint32_t currentIblSpecularMipmapLevels = (mDiffuseTexture && mSpecularTexture) ? mSpecularMipmapLevels : mSceneSpecularMipmapLevels;
1098 if(!currentDiffuseTexture || !currentSpecularTexture)
1100 currentDiffuseTexture = mDefaultDiffuseTexture;
1101 currentSpecularTexture = mDefaultSpecularTexture;
1102 currentIblScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
1103 currentIblSpecularMipmapLevels = 1u;
1106 UpdateImageBasedLightTextureRecursively(mModelRoot, currentDiffuseTexture, currentSpecularTexture, currentIblScaleFactor, currentIblSpecularMipmapLevels);
1109 void Model::UpdateImageBasedLightScaleFactor()
1111 if((!mDiffuseTexture || !mSpecularTexture) &&
1112 (!mSceneDiffuseTexture || !mSceneSpecularTexture))
1117 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
1118 UpdateImageBasedLightScaleFactorRecursively(mModelRoot, currentIblScaleFactor);
1121 void Model::ApplyCameraTransform(Dali::CameraActor camera) const
1123 Vector3 selfPosition = Self().GetProperty<Vector3>(Actor::Property::POSITION);
1124 Quaternion selfOrientation = Self().GetProperty<Quaternion>(Actor::Property::ORIENTATION);
1125 Vector3 selfScale = Self().GetProperty<Vector3>(Actor::Property::SCALE);
1127 Vector3 cameraPosition = camera.GetProperty<Vector3>(Actor::Property::POSITION);
1128 Quaternion cameraOrientation = camera.GetProperty<Quaternion>(Actor::Property::ORIENTATION);
1129 Vector3 cameraScale = camera.GetProperty<Vector3>(Actor::Property::SCALE);
1131 // Models in glTF and dli are defined as right hand coordinate system.
1132 // DALi uses left hand coordinate system. Scaling negative is for change winding order.
1133 if(!Dali::Equals(Y_DIRECTION.Dot(Vector3::YAXIS), 1.0f))
1135 // Reflect by XZ plane
1136 cameraPosition.y = -cameraPosition.y;
1137 Quaternion yDirectionQuaternion;
1138 yDirectionQuaternion.mVector = Vector3::YAXIS;
1139 // Reflect orientation
1140 cameraOrientation = yDirectionQuaternion * cameraOrientation * yDirectionQuaternion;
1143 Vector3 resultPosition;
1144 Quaternion resultOrientation;
1145 Vector3 resultScale;
1147 Matrix selfMatrix(false);
1148 Matrix cameraMatrix(false);
1149 Matrix resultMatrix(false);
1150 selfMatrix.SetTransformComponents(selfScale, selfOrientation, selfPosition);
1151 cameraMatrix.SetTransformComponents(cameraScale, cameraOrientation, cameraPosition);
1152 Matrix::Multiply(resultMatrix, cameraMatrix, selfMatrix);
1153 resultMatrix.GetTransformComponents(resultPosition, resultOrientation, resultScale);
1155 camera.SetProperty(Actor::Property::POSITION, resultPosition);
1156 camera.SetProperty(Actor::Property::ORIENTATION, resultOrientation);
1157 camera.SetProperty(Actor::Property::SCALE, resultScale);
1160 void Model::NotifyShadowMapTexture(Dali::Texture shadowMapTexture)
1162 if(mShadowMapTexture != shadowMapTexture)
1164 mShadowMapTexture = shadowMapTexture;
1165 UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture);
1169 void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels)
1171 if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
1173 mSceneDiffuseTexture = diffuseTexture;
1174 mSceneSpecularTexture = specularTexture;
1175 mSceneIblScaleFactor = scaleFactor;
1176 mSceneSpecularMipmapLevels = specularMipmapLevels;
1177 // If Model IBL is not set, use SceneView's IBL.
1178 if(!mDiffuseTexture || !mSpecularTexture)
1180 UpdateImageBasedLightTexture();
1185 void Model::NotifyImageBasedLightScaleFactor(float scaleFactor)
1187 mSceneIblScaleFactor = scaleFactor;
1188 if(mSceneDiffuseTexture && mSceneSpecularTexture)
1190 UpdateImageBasedLightScaleFactor();
1194 void Model::OnModelLoadComplete()
1196 IntrusivePtr<Model> self = this; // Keep reference until this API finished
1198 if(!mModelLoadTask->HasSucceeded())
1200 ResetResourceTasks();
1202 if(ModelCacheManager::Get() && !mModelUrl.empty())
1204 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
1216 auto& resources = mModelLoadTask->GetResources();
1217 auto& scene = mModelLoadTask->GetScene();
1218 CreateAnimations(scene);
1219 ResetCameraParameters();
1220 if(!resources.mEnvironmentMaps.empty())
1222 if(resources.mEnvironmentMaps.front().second.mDiffuse)
1224 mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse;
1226 if(resources.mEnvironmentMaps.front().second.mSpecular)
1228 mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
1232 if(mShadowMapTexture)
1234 UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture);
1236 UpdateImageBasedLightTexture();
1237 UpdateImageBasedLightScaleFactor();
1238 Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
1240 mModelResourceReady = true;
1241 ResetResourceTask(mModelLoadTask);
1242 NotifyResourceReady();
1245 void Model::OnIblDiffuseLoadComplete()
1247 mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
1248 ResetResourceTask(mIblDiffuseLoadTask);
1249 mIblDiffuseResourceReady = true;
1250 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1252 OnIblLoadComplete();
1256 void Model::OnIblSpecularLoadComplete()
1258 mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
1259 mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
1260 ResetResourceTask(mIblSpecularLoadTask);
1261 mIblSpecularResourceReady = true;
1262 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1264 OnIblLoadComplete();
1268 void Model::OnIblLoadComplete()
1270 UpdateImageBasedLightTexture();
1271 NotifyResourceReady();
1274 void Model::OnSizeNotification(Dali::PropertyNotification& source)
1279 void Model::ResetResourceTasks()
1281 if(!Dali::Adaptor::IsAvailable())
1285 ResetResourceTask(mModelLoadTask);
1286 ResetResourceTask(mIblDiffuseLoadTask);
1287 ResetResourceTask(mIblSpecularLoadTask);
1290 void Model::NotifyResourceReady()
1292 if(!IsResourceReady())
1296 Control::SetResourceReady();
1299 void Model::CreateModel()
1301 BoundingVolume AABB;
1302 auto& resources = mModelLoadTask->GetResources();
1303 auto& scene = mModelLoadTask->GetScene();
1304 auto& resourceChoices = mModelLoadTask->GetResourceChoices();
1305 Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
1307 Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, mShaderManager, {}, {}, {}};
1309 // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
1310 resources.GenerateResources();
1311 for(auto iRoot : scene.GetRoots())
1313 if(auto modelNode = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
1315 scene.ConfigureSkinningShaders(resources, modelNode, std::move(nodeParams.mSkinnables));
1316 ConfigureBlendShapeShaders(resources, scene, modelNode, std::move(nodeParams.mBlendshapeRequests));
1318 scene.ApplyConstraints(modelNode, std::move(nodeParams.mConstrainables));
1320 mModelRoot.Add(modelNode);
1323 AddModelTreeToAABB(AABB, scene, resourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
1326 UpdateBlendShapeNodeMap();
1328 mNaturalSize = AABB.CalculateSize();
1329 mModelPivot = AABB.CalculatePivot();
1330 mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1331 Vector3 controlSize = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
1332 if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y))
1334 Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1340 void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
1342 mAnimations.clear();
1343 if(!mModelLoadTask->GetAnimations().empty())
1345 auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
1346 if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
1348 return mModelRoot.FindChildByName(property.mNodeName);
1350 auto* node = scene.GetNode(property.mNodeIndex);
1353 return Dali::Actor();
1355 return mModelRoot.FindChildById(node->mNodeId);
1358 for(auto&& animation : mModelLoadTask->GetAnimations())
1360 Dali::Animation anim = animation.ReAnimate(getActor);
1361 mAnimations.push_back({animation.GetName(), anim});
1366 void Model::ResetCameraParameters()
1368 mCameraParameters.clear();
1369 if(!mModelLoadTask->GetCameras().empty())
1371 // Copy camera parameters.
1372 std::copy(mModelLoadTask->GetCameras().begin(), mModelLoadTask->GetCameras().end(), std::back_inserter(mCameraParameters));
1376 void Model::UpdateBlendShapeNodeMap()
1378 // Remove privous node map
1379 mBlendShapeModelNodeMap.clear();
1381 UpdateBlendShapeNodeMapRecursively(mBlendShapeModelNodeMap, mModelRoot);
1384 } // namespace Internal
1385 } // namespace Scene3D