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>
46 #include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
59 * Creates control through type registry
63 return Scene3D::Model::New(std::string());
66 // Setup properties, signals and actions using the type-registry.
67 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Model, Toolkit::Control, Create);
68 DALI_TYPE_REGISTRATION_END()
70 static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f);
71 static constexpr float SIZE_STEP_CONDITION = 0.1f;
73 static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false;
74 static constexpr bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false;
80 pointMin = Vector3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
81 pointMax = Vector3(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
84 void ConsiderNewPointInVolume(const Vector3& position)
86 pointMin.x = std::min(position.x, pointMin.x);
87 pointMin.y = std::min(position.y, pointMin.y);
88 pointMin.z = std::min(position.z, pointMin.z);
90 pointMax.x = std::max(position.x, pointMax.x);
91 pointMax.y = std::max(position.y, pointMax.y);
92 pointMax.z = std::max(position.z, pointMax.z);
95 Vector3 CalculateSize()
97 return pointMax - pointMin;
100 Vector3 CalculatePivot()
102 Vector3 pivot = pointMin / (pointMin - pointMax);
103 for(uint32_t i = 0; i < 3; ++i)
105 // To avoid divid by zero
106 if(Dali::Equals(pointMin[i], pointMax[i]))
118 void ConfigureBlendShapeShaders(
119 Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
121 std::vector<std::string> errors;
122 auto onError = [&errors](const std::string& msg) { errors.push_back(msg); };
123 if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
125 Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
126 for(auto& msg : errors)
128 flinger << msg << '\n';
133 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)
135 static constexpr uint32_t BOX_POINT_COUNT = 8;
136 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}};
139 const Dali::Scene3D::Loader::NodeDefinition* node = scene.GetNode(iNode);
140 Matrix localMatrix = node->GetLocalSpace();
141 Matrix::Multiply(nodeMatrix, localMatrix, parentMatrix);
144 if(node->GetExtents(nodeParams.mResources, volume[0], volume[1]))
146 for(uint32_t i = 0; i < BOX_POINT_COUNT; ++i)
148 Vector4 position = Vector4(volume[BBIndex[i][0]].x, volume[BBIndex[i][1]].y, volume[BBIndex[i][2]].z, 1.0f);
149 Vector4 objectPosition = nodeMatrix * position;
150 objectPosition /= objectPosition.w;
152 AABB.ConsiderNewPointInVolume(Vector3(objectPosition));
156 if(node->mCustomization)
158 if(!node->mChildren.empty())
160 auto choice = choices.Get(node->mCustomization->mTag);
161 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));
163 AddModelTreeToAABB(AABB, scene, choices, node->mChildren[i], nodeParams, nodeMatrix);
168 for(auto i : node->mChildren)
170 AddModelTreeToAABB(AABB, scene, choices, i, nodeParams, nodeMatrix);
175 void AddLightRecursively(Scene3D::ModelNode node, Scene3D::Light light, uint32_t lightIndex)
181 GetImplementation(node).AddLight(light, lightIndex);
183 uint32_t childrenCount = node.GetChildCount();
184 for(uint32_t i = 0; i < childrenCount; ++i)
186 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
189 AddLightRecursively(childNode, light, lightIndex);
194 void RemoveLightRecursively(Scene3D::ModelNode node, uint32_t lightIndex)
201 GetImplementation(node).RemoveLight(lightIndex);
203 uint32_t childrenCount = node.GetChildCount();
204 for(uint32_t i = 0; i < childrenCount; ++i)
206 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
209 RemoveLightRecursively(childNode, lightIndex);
214 void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node)
220 const auto childCount = node.GetChildCount();
221 for(auto i = 0u; i < childCount; ++i)
223 UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i)));
226 std::vector<std::string> blendShapeNames;
227 node.RetrieveBlendShapeNames(blendShapeNames);
228 for(const auto& iter : blendShapeNames)
230 // Append or create new list.
231 resultMap[iter].push_back(node);
235 } // anonymous namespace
237 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
238 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
240 mResourceDirectoryUrl(resourceDirectoryUrl),
242 mNaturalSize(Vector3::ZERO),
243 mModelPivot(AnchorPoint::CENTER),
244 mSceneIblScaleFactor(1.0f),
245 mIblScaleFactor(1.0f),
246 mSceneSpecularMipmapLevels(1u),
247 mSpecularMipmapLevels(1u),
248 mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE),
249 mModelChildrenFocusable(DEFAULT_MODEL_CHILDREN_FOCUSABLE),
250 mModelResourceReady(false),
251 mIblDiffuseResourceReady(true),
252 mIblSpecularResourceReady(true),
253 mIblDiffuseDirty(false),
254 mIblSpecularDirty(false)
260 ResetResourceTasks();
262 if(ModelCacheManager::Get() && !mModelUrl.empty())
264 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
268 Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
270 Model* impl = new Model(modelUrl, resourceDirectoryUrl);
272 Dali::Scene3D::Model handle = Dali::Scene3D::Model(*impl);
274 // Second-phase init of the implementation
275 // This can only be done after the CustomActor connection has been made...
281 const Scene3D::ModelNode Model::GetModelRoot() const
286 void Model::AddModelNode(Scene3D::ModelNode modelNode)
293 mModelRoot.Add(modelNode);
294 if(mModelUrl.empty())
296 mModelResourceReady = true;
299 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
301 UpdateImageBasedLightTexture();
302 UpdateImageBasedLightScaleFactor();
305 uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
306 for(uint32_t i = 0; i < maxLightCount; ++i)
310 AddLightRecursively(modelNode, mLights[i], i);
314 if(Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
316 NotifyResourceReady();
320 void Model::RemoveModelNode(Scene3D::ModelNode modelNode)
324 uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
325 for(uint32_t i = 0; i < maxLightCount; ++i)
329 RemoveLightRecursively(modelNode, i);
332 mModelRoot.Remove(modelNode);
336 void Model::SetChildrenSensitive(bool enable)
338 if(mModelChildrenSensitive != enable)
340 mModelChildrenSensitive = enable;
343 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
348 bool Model::GetChildrenSensitive() const
350 return mModelChildrenSensitive;
353 void Model::SetChildrenFocusable(bool enable)
355 if(mModelChildrenFocusable != enable)
357 mModelChildrenFocusable = enable;
360 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
361 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
366 bool Model::GetChildrenFocusable() const
368 return mModelChildrenFocusable;
371 void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
373 bool needIblReset = false;
374 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
375 if(mDiffuseIblUrl != diffuseUrl)
377 mDiffuseIblUrl = diffuseUrl;
378 if(mDiffuseIblUrl.empty())
384 mIblDiffuseDirty = true;
385 mIblDiffuseResourceReady = false;
389 if(mSpecularIblUrl != specularUrl)
391 mSpecularIblUrl = specularUrl;
392 if(mSpecularIblUrl.empty())
398 mIblSpecularDirty = true;
399 mIblSpecularResourceReady = false;
403 // If one or both of diffuse url and specular url are empty,
404 // we don't need to request to load texture.
407 ResetResourceTask(mIblDiffuseLoadTask);
408 ResetResourceTask(mIblSpecularLoadTask);
410 mIblDiffuseDirty = false;
411 mIblSpecularDirty = false;
412 mIblDiffuseResourceReady = true;
413 mIblSpecularResourceReady = true;
415 mDiffuseTexture.Reset();
416 mSpecularTexture.Reset();
417 UpdateImageBasedLightTexture();
421 if(isOnScene && mIblDiffuseDirty)
423 ResetResourceTask(mIblDiffuseLoadTask);
424 mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete));
425 Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
426 mIblDiffuseDirty = false;
429 if(isOnScene && mIblSpecularDirty)
431 ResetResourceTask(mIblSpecularLoadTask);
432 mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete));
433 Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
434 mIblSpecularDirty = false;
438 if(!Dali::Equals(mIblScaleFactor, scaleFactor))
440 mIblScaleFactor = scaleFactor;
441 UpdateImageBasedLightScaleFactor();
444 // If diffuse and specular textures are already loaded, emits resource ready signal here.
445 NotifyResourceReady();
448 void Model::SetImageBasedLightScaleFactor(float scaleFactor)
450 mIblScaleFactor = scaleFactor;
451 if(mDiffuseTexture && mSpecularTexture)
453 UpdateImageBasedLightScaleFactor();
457 float Model::GetImageBasedLightScaleFactor() const
459 return mIblScaleFactor;
462 uint32_t Model::GetAnimationCount() const
464 return mAnimations.size();
467 Dali::Animation Model::GetAnimation(uint32_t index) const
469 Dali::Animation animation;
470 if(mAnimations.size() > index)
472 animation = mAnimations[index].second;
477 Dali::Animation Model::GetAnimation(const std::string& name) const
479 Dali::Animation animation;
482 for(auto&& animationData : mAnimations)
484 if(animationData.first == name)
486 animation = animationData.second;
494 uint32_t Model::GetCameraCount() const
496 return mCameraParameters.size();
499 Dali::CameraActor Model::GenerateCamera(uint32_t index) const
501 Dali::CameraActor camera;
502 if(mCameraParameters.size() > index)
504 camera = Dali::CameraActor::New3DCamera();
505 if(!mCameraParameters[index].ConfigureCamera(camera, false))
507 DALI_LOG_ERROR("Fail to generate %u's camera actor : Some property was not defined. Please check model file.\n", index);
512 ApplyCameraTransform(camera);
517 bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const
519 if(camera && mCameraParameters.size() > index)
521 if(!mCameraParameters[index].ConfigureCamera(camera, false))
523 DALI_LOG_ERROR("Fail to apply %u's camera actor : Some property was not defined. Please check model file.\n", index);
527 ApplyCameraTransform(camera);
533 Scene3D::ModelNode Model::FindChildModelNodeByName(std::string_view nodeName)
535 Actor childActor = Self().FindChildByName(nodeName);
536 return Scene3D::ModelNode::DownCast(childActor);
539 void Model::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
541 blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeModelNodeMap.size());
542 for(const auto& iter : mBlendShapeModelNodeMap)
544 blendShapeNames.push_back(iter.first);
548 void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<Scene3D::ModelNode>& modelNodes) const
550 auto iter = mBlendShapeModelNodeMap.find(std::string(blendShapeName));
551 if(iter != mBlendShapeModelNodeMap.end())
553 const auto& modelNodeList = iter->second;
554 modelNodes.reserve(modelNodes.size() + modelNodeList.size());
555 for(const auto& nodeIter : modelNodeList)
557 modelNodes.push_back(nodeIter);
562 Dali::Animation Model::GenerateMotionDataAnimation(Scene3D::MotionData motionData)
564 Dali::Animation animation;
566 // TODO : Need to collect duplicated codes with SetMotionData()
570 const uint32_t motionCount = motionData.GetMotionCount();
571 for(uint32_t i = 0u; i < motionCount; ++i)
573 auto motionIndex = motionData.GetIndex(i);
574 auto motionValue = motionData.GetValue(i);
575 if(motionIndex && motionValue)
577 if(motionIndex.GetModelNodeId() != Property::INVALID_KEY)
579 Scene3D::ModelNode modelNode;
580 if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING)
582 modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey);
584 else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX)
586 // TODO : Not implement yet.
591 KeyFrames keyFrames = motionValue.GetKeyFrames();
595 // Try to use index first. If failed, try to use name
596 Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode);
597 if(animatedPropertyIndex != Property::INVALID_INDEX)
599 if(DALI_UNLIKELY(!animation))
601 animation = Animation::New(motionData.GetDuration());
603 animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames);
607 std::string animatedPropertyName = motionIndex.GetPropertyName(modelNode);
608 Dali::Property property(modelNode, animatedPropertyName);
609 if(property.propertyIndex != Property::INVALID_INDEX)
611 if(DALI_UNLIKELY(!animation))
613 animation = Animation::New(motionData.GetDuration());
615 animation.AnimateBetween(property, keyFrames);
623 Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex);
624 if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING)
626 // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId,
627 // we need to animate all kind of blendshapes
629 KeyFrames keyFrames = motionValue.GetKeyFrames();
633 std::vector<Scene3D::ModelNode> modelNodes;
634 RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes);
636 for(auto& modelNode : modelNodes)
638 // Try to use index first. If failed, try to use name
639 Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode);
640 if(animatedPropertyIndex != Property::INVALID_INDEX)
642 if(DALI_UNLIKELY(!animation))
644 animation = Animation::New(motionData.GetDuration());
646 animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames);
650 std::string animatedPropertyName = motionIndex.GetPropertyName(modelNode);
651 Dali::Property property(modelNode, animatedPropertyName);
653 if(property.propertyIndex != Property::INVALID_INDEX)
655 if(DALI_UNLIKELY(!animation))
657 animation = Animation::New(motionData.GetDuration());
659 animation.AnimateBetween(property, keyFrames);
673 void Model::SetMotionData(Scene3D::MotionData motionData)
675 // TODO : Need to collect duplicated codes with GenerateMotionDataAnimation()
679 const uint32_t motionCount = motionData.GetMotionCount();
680 for(uint32_t i = 0u; i < motionCount; ++i)
682 auto motionIndex = motionData.GetIndex(i);
683 auto motionValue = motionData.GetValue(i);
684 if(motionIndex && motionValue)
686 if(motionIndex.GetModelNodeId() != Property::INVALID_KEY)
688 Scene3D::ModelNode modelNode;
689 if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING)
691 modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey);
693 else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX)
695 // TODO : Not implement yet.
700 Property::Value value = motionValue.GetPropertyValue();
702 if(value.GetType() != Property::Type::NONE)
704 // Try to use index first. If failed, try to use name
705 Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode);
706 if(propertyIndex != Property::INVALID_INDEX)
708 modelNode.SetProperty(propertyIndex, value);
712 std::string propertyName = motionIndex.GetPropertyName(modelNode);
713 Dali::Property property(modelNode, propertyName);
714 if(property.propertyIndex != Property::INVALID_INDEX)
716 modelNode.SetProperty(property.propertyIndex, value);
724 Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex);
725 if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING)
727 // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId,
728 // we need to animate all kind of blendshapes
730 Property::Value value = motionValue.GetPropertyValue();
732 if(value.GetType() != Property::Type::NONE)
734 std::vector<Scene3D::ModelNode> modelNodes;
735 RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes);
737 for(auto& modelNode : modelNodes)
739 // Try to use index first. If failed, try to use name
740 Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode);
741 if(propertyIndex != Property::INVALID_INDEX)
743 modelNode.SetProperty(propertyIndex, value);
747 std::string propertyName = motionIndex.GetPropertyName(modelNode);
748 Dali::Property property(modelNode, propertyName);
749 if(property.propertyIndex != Property::INVALID_INDEX)
751 modelNode.SetProperty(property.propertyIndex, value);
763 ///////////////////////////////////////////////////////////
768 void Model::OnInitialize()
770 // Make ParentOrigin as Center.
771 Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
772 mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount());
775 void Model::OnSceneConnection(int depth)
777 if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty())
779 // Request model load only if we setup url.
780 if(ModelCacheManager::Get())
782 ModelCacheManager::Get().ReferenceModelCache(mModelUrl);
784 mModelLoadTask = new ModelLoadTask(mModelUrl, mResourceDirectoryUrl, MakeCallback(this, &Model::OnModelLoadComplete));
785 Dali::AsyncTaskManager::Get().AddTask(mModelLoadTask);
788 // If diffuse and specular url is not valid, IBL does not need to be loaded.
789 if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
791 SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
794 Actor parent = Self().GetParent();
797 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
800 GetImpl(sceneView).RegisterSceneItem(this);
801 mParentSceneView = sceneView;
804 parent = parent.GetParent();
807 NotifyResourceReady();
809 mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION));
810 mSizeNotification.NotifySignal().Connect(this, &Model::OnSizeNotification);
811 Control::OnSceneConnection(depth);
814 void Model::OnSceneDisconnection()
816 Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
819 GetImpl(sceneView).UnregisterSceneItem(this);
820 mParentSceneView.Reset();
823 mSizeNotification.NotifySignal().Disconnect(this, &Model::OnSizeNotification);
824 Self().RemovePropertyNotification(mSizeNotification);
825 mSizeNotification.Reset();
827 Control::OnSceneDisconnection();
830 void Model::OnSizeSet(const Vector3& size)
835 Vector3 Model::GetNaturalSize()
839 DALI_LOG_ERROR("Model is still not loaded.\n");
840 return Vector3::ZERO;
846 float Model::GetHeightForWidth(float width)
849 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
850 return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
853 float Model::GetWidthForHeight(float height)
856 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
857 return Control::GetWidthForHeight(height) + padding.start + padding.end;
860 void Model::OnRelayout(const Vector2& size, RelayoutContainer& container)
862 Control::OnRelayout(size, container);
866 bool Model::IsResourceReady() const
868 return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady;
871 void Model::CreateModelRoot()
873 mModelRoot = Scene3D::ModelNode::New();
874 mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
875 mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION);
876 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
877 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
878 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
879 Self().Add(mModelRoot);
882 void Model::ScaleModel(bool useCurrentSize)
890 Vector3 size = (useCurrentSize) ? Self().GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE) : Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
891 if(size.x > 0.0f && size.y > 0.0f)
894 scale = std::min(size.x / mNaturalSize.x, scale);
895 scale = std::min(size.y / mNaturalSize.y, scale);
897 // Models in glTF and dli are defined as right hand coordinate system.
898 // DALi uses left hand coordinate system. Scaling negative is for change winding order.
899 mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale);
902 void Model::FitModelPosition()
908 // Loaded model pivot is not the model center.
909 mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
910 mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
913 void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
920 GetImplementation(node).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
921 uint32_t childrenCount = node.GetChildCount();
922 for(uint32_t i = 0; i < childrenCount; ++i)
924 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
929 UpdateImageBasedLightTextureRecursively(childNode, diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
933 void Model::UpdateImageBasedLightScaleFactorRecursively(Scene3D::ModelNode node, float iblScaleFactor)
940 GetImplementation(node).SetImageBasedLightScaleFactor(iblScaleFactor);
942 uint32_t childrenCount = node.GetChildCount();
943 for(uint32_t i = 0; i < childrenCount; ++i)
945 Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
950 UpdateImageBasedLightScaleFactorRecursively(childNode, iblScaleFactor);
954 void Model::UpdateImageBasedLightTexture()
956 Dali::Texture currentDiffuseTexture = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture;
957 Dali::Texture currentSpecularTexture = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture;
958 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
959 uint32_t currentIblSpecularMipmapLevels = (mDiffuseTexture && mSpecularTexture) ? mSpecularMipmapLevels : mSceneSpecularMipmapLevels;
961 if(!currentDiffuseTexture || !currentSpecularTexture)
963 currentDiffuseTexture = mDefaultDiffuseTexture;
964 currentSpecularTexture = mDefaultSpecularTexture;
965 currentIblScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
966 currentIblSpecularMipmapLevels = 1u;
969 UpdateImageBasedLightTextureRecursively(mModelRoot, currentDiffuseTexture, currentSpecularTexture, currentIblScaleFactor, currentIblSpecularMipmapLevels);
972 void Model::UpdateImageBasedLightScaleFactor()
974 if((!mDiffuseTexture || !mSpecularTexture) &&
975 (!mSceneDiffuseTexture || !mSceneSpecularTexture))
980 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
981 UpdateImageBasedLightScaleFactorRecursively(mModelRoot, currentIblScaleFactor);
984 void Model::ApplyCameraTransform(Dali::CameraActor camera) const
986 Vector3 selfPosition = Self().GetProperty<Vector3>(Actor::Property::POSITION);
987 Quaternion selfOrientation = Self().GetProperty<Quaternion>(Actor::Property::ORIENTATION);
988 Vector3 selfScale = Self().GetProperty<Vector3>(Actor::Property::SCALE);
990 Vector3 cameraPosition = camera.GetProperty<Vector3>(Actor::Property::POSITION);
991 Quaternion cameraOrientation = camera.GetProperty<Quaternion>(Actor::Property::ORIENTATION);
992 Vector3 cameraScale = camera.GetProperty<Vector3>(Actor::Property::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 if(!Dali::Equals(Y_DIRECTION.Dot(Vector3::YAXIS), 1.0f))
998 // Reflect by XZ plane
999 cameraPosition.y = -cameraPosition.y;
1000 Quaternion yDirectionQuaternion;
1001 yDirectionQuaternion.mVector = Vector3::YAXIS;
1002 // Reflect orientation
1003 cameraOrientation = yDirectionQuaternion * cameraOrientation * yDirectionQuaternion;
1006 Vector3 resultPosition;
1007 Quaternion resultOrientation;
1008 Vector3 resultScale;
1010 Matrix selfMatrix(false);
1011 Matrix cameraMatrix(false);
1012 Matrix resultMatrix(false);
1013 selfMatrix.SetTransformComponents(selfScale, selfOrientation, selfPosition);
1014 cameraMatrix.SetTransformComponents(cameraScale, cameraOrientation, cameraPosition);
1015 Matrix::Multiply(resultMatrix, cameraMatrix, selfMatrix);
1016 resultMatrix.GetTransformComponents(resultPosition, resultOrientation, resultScale);
1018 camera.SetProperty(Actor::Property::POSITION, resultPosition);
1019 camera.SetProperty(Actor::Property::ORIENTATION, resultOrientation);
1020 camera.SetProperty(Actor::Property::SCALE, resultScale);
1023 void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels)
1025 if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
1027 mSceneDiffuseTexture = diffuseTexture;
1028 mSceneSpecularTexture = specularTexture;
1029 mSceneIblScaleFactor = scaleFactor;
1030 mSceneSpecularMipmapLevels = specularMipmapLevels;
1031 // If Model IBL is not set, use SceneView's IBL.
1032 if(!mDiffuseTexture || !mSpecularTexture)
1034 UpdateImageBasedLightTexture();
1039 void Model::NotifyImageBasedLightScaleFactor(float scaleFactor)
1041 mSceneIblScaleFactor = scaleFactor;
1042 if(mSceneDiffuseTexture && mSceneSpecularTexture)
1044 UpdateImageBasedLightScaleFactor();
1048 void Model::NotifyLightAdded(uint32_t lightIndex, Scene3D::Light light)
1050 mLights[lightIndex] = light;
1051 AddLightRecursively(mModelRoot, light, lightIndex);
1054 void Model::NotifyLightRemoved(uint32_t lightIndex)
1056 if(mLights[lightIndex])
1058 RemoveLightRecursively(mModelRoot, lightIndex);
1059 mLights[lightIndex].Reset();
1063 void Model::OnModelLoadComplete()
1065 if(!mModelLoadTask->HasSucceeded())
1067 ResetResourceTasks();
1069 if(ModelCacheManager::Get() && !mModelUrl.empty())
1071 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
1083 auto& resources = mModelLoadTask->GetResources();
1084 auto& scene = mModelLoadTask->GetScene();
1085 CreateAnimations(scene);
1086 ResetCameraParameters();
1087 if(!resources.mEnvironmentMaps.empty())
1089 mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse;
1090 mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
1093 uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
1094 for(uint32_t i = 0; i < maxLightCount; ++i)
1098 AddLightRecursively(mModelRoot, mLights[i], i);
1102 UpdateImageBasedLightTexture();
1103 UpdateImageBasedLightScaleFactor();
1104 Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
1106 mModelResourceReady = true;
1107 NotifyResourceReady();
1108 ResetResourceTask(mModelLoadTask);
1111 void Model::OnIblDiffuseLoadComplete()
1113 mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
1114 ResetResourceTask(mIblDiffuseLoadTask);
1115 mIblDiffuseResourceReady = true;
1116 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1118 OnIblLoadComplete();
1122 void Model::OnIblSpecularLoadComplete()
1124 mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
1125 mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
1126 ResetResourceTask(mIblSpecularLoadTask);
1127 mIblSpecularResourceReady = true;
1128 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1130 OnIblLoadComplete();
1134 void Model::OnIblLoadComplete()
1136 UpdateImageBasedLightTexture();
1137 NotifyResourceReady();
1140 void Model::OnSizeNotification(Dali::PropertyNotification& source)
1145 void Model::ResetResourceTasks()
1147 if(!Dali::Adaptor::IsAvailable())
1151 ResetResourceTask(mModelLoadTask);
1152 ResetResourceTask(mIblDiffuseLoadTask);
1153 ResetResourceTask(mIblSpecularLoadTask);
1156 void Model::ResetResourceTask(IntrusivePtr<AsyncTask> asyncTask)
1162 Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
1166 void Model::NotifyResourceReady()
1168 if(!IsResourceReady())
1172 Control::SetResourceReady();
1175 void Model::CreateModel()
1177 BoundingVolume AABB;
1178 auto& resources = mModelLoadTask->GetResources();
1179 auto& scene = mModelLoadTask->GetScene();
1180 auto& resourceChoices = mModelLoadTask->GetResourceChoices();
1181 Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
1182 Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, {}, {}, {}};
1184 // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
1185 resources.GenerateResources();
1186 for(auto iRoot : scene.GetRoots())
1188 if(auto modelNode = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
1190 scene.ConfigureSkinningShaders(resources, modelNode, std::move(nodeParams.mSkinnables));
1191 ConfigureBlendShapeShaders(resources, scene, modelNode, std::move(nodeParams.mBlendshapeRequests));
1193 scene.ApplyConstraints(modelNode, std::move(nodeParams.mConstrainables));
1195 mModelRoot.Add(modelNode);
1198 AddModelTreeToAABB(AABB, scene, resourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
1201 UpdateBlendShapeNodeMap();
1203 mNaturalSize = AABB.CalculateSize();
1204 mModelPivot = AABB.CalculatePivot();
1205 mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1206 Vector3 controlSize = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
1207 if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y))
1209 Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1215 void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
1217 mAnimations.clear();
1218 if(!mModelLoadTask->GetAnimations().empty())
1220 auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
1221 if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
1223 return mModelRoot.FindChildByName(property.mNodeName);
1225 auto* node = scene.GetNode(property.mNodeIndex);
1228 return Dali::Actor();
1230 return mModelRoot.FindChildById(node->mNodeId);
1233 for(auto&& animation : mModelLoadTask->GetAnimations())
1235 Dali::Animation anim = animation.ReAnimate(getActor);
1236 mAnimations.push_back({animation.GetName(), anim});
1241 void Model::ResetCameraParameters()
1243 mCameraParameters.clear();
1244 if(!mModelLoadTask->GetCameras().empty())
1246 // Copy camera parameters.
1247 std::copy(mModelLoadTask->GetCameras().begin(), mModelLoadTask->GetCameras().end(), std::back_inserter(mCameraParameters));
1251 void Model::UpdateBlendShapeNodeMap()
1253 // Remove privous node map
1254 mBlendShapeModelNodeMap.clear();
1256 UpdateBlendShapeNodeMapRecursively(mBlendShapeModelNodeMap, mModelRoot);
1259 } // namespace Internal
1260 } // namespace Scene3D