X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-scene3d%2Finternal%2Fcontrols%2Fmodel%2Fmodel-impl.cpp;h=f012aa6ac9ce8668513f6801add26c9a90637705;hb=HEAD;hp=7c82d4b6969b45178b90d88bd842950aaa5e6b54;hpb=f8c5751dd0c375ecbfafa72b7c1ac36fe3d060fd;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-scene3d/internal/controls/model/model-impl.cpp b/dali-scene3d/internal/controls/model/model-impl.cpp index 7c82d4b..f012aa6 100644 --- a/dali-scene3d/internal/controls/model/model-impl.cpp +++ b/dali-scene3d/internal/controls/model/model-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,8 +31,10 @@ #include // INTERNAL INCLUDES +#include #include #include +#include #include #include #include @@ -42,9 +44,9 @@ #include #include #include -#include +#include #include - +#include using namespace Dali; namespace Dali @@ -172,33 +174,35 @@ void AddModelTreeToAABB(BoundingVolume& AABB, const Dali::Scene3D::Loader::Scene } } -void AddLightRecursively(Scene3D::ModelNode node, Scene3D::Light light, uint32_t lightIndex) +void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node) { if(!node) { return; } - GetImplementation(node).AddLight(light, lightIndex); + const auto childCount = node.GetChildCount(); + for(auto i = 0u; i < childCount; ++i) + { + UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i))); + } - uint32_t childrenCount = node.GetChildCount(); - for(uint32_t i = 0; i < childrenCount; ++i) + std::vector blendShapeNames; + node.RetrieveBlendShapeNames(blendShapeNames); + for(const auto& iter : blendShapeNames) { - Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i)); - if(childNode) - { - AddLightRecursively(childNode, light, lightIndex); - } + // Append or create new list. + resultMap[iter].push_back(node); } } -void RemoveLightRecursively(Scene3D::ModelNode node, uint32_t lightIndex) +void UpdateShaderRecursively(Scene3D::ModelNode node, Scene3D::Loader::ShaderManagerPtr shaderManager) { if(!node) { return; } - GetImplementation(node).RemoveLight(lightIndex); + GetImplementation(node).UpdateShader(shaderManager); uint32_t childrenCount = node.GetChildCount(); for(uint32_t i = 0; i < childrenCount; ++i) @@ -206,30 +210,39 @@ void RemoveLightRecursively(Scene3D::ModelNode node, uint32_t lightIndex) Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i)); if(childNode) { - RemoveLightRecursively(childNode, lightIndex); + UpdateShaderRecursively(childNode, shaderManager); } } } -void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node) +void UpdateShadowMapTextureRecursively(Scene3D::ModelNode node, Dali::Texture shadowMapTexture) { if(!node) { return; } - const auto childCount = node.GetChildCount(); - for(auto i = 0u; i < childCount; ++i) + + GetImplementation(node).SetShadowMapTexture(shadowMapTexture); + + uint32_t childrenCount = node.GetChildCount(); + for(uint32_t i = 0; i < childrenCount; ++i) { - UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i))); + Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i)); + if(childNode) + { + UpdateShadowMapTextureRecursively(childNode, shadowMapTexture); + } } +} - std::vector blendShapeNames; - node.RetrieveBlendShapeNames(blendShapeNames); - for(const auto& iter : blendShapeNames) +void ResetResourceTask(IntrusivePtr&& asyncTask) +{ + if(!asyncTask) { - // Append or create new list. - resultMap[iter].push_back(node); + return; } + Dali::AsyncTaskManager::Get().RemoveTask(asyncTask); + asyncTask.Reset(); } } // anonymous namespace @@ -239,6 +252,7 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr mModelUrl(modelUrl), mResourceDirectoryUrl(resourceDirectoryUrl), mModelRoot(), + mShaderManager(new Scene3D::Loader::ShaderManager()), mNaturalSize(Vector3::ZERO), mModelPivot(AnchorPoint::CENTER), mSceneIblScaleFactor(1.0f), @@ -251,7 +265,9 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr mIblDiffuseResourceReady(true), mIblSpecularResourceReady(true), mIblDiffuseDirty(false), - mIblSpecularDirty(false) + mIblSpecularDirty(false), + mIsShadowCasting(true), + mIsShadowReceiving(true) { } @@ -296,19 +312,26 @@ void Model::AddModelNode(Scene3D::ModelNode modelNode) mModelResourceReady = true; } + UpdateShaderRecursively(modelNode, mShaderManager); + + if(mShadowMapTexture) + { + UpdateShadowMapTextureRecursively(modelNode, mShadowMapTexture); + } + if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { UpdateImageBasedLightTexture(); UpdateImageBasedLightScaleFactor(); } - uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount(); - for(uint32_t i = 0; i < maxLightCount; ++i) + GetImplementation(modelNode).SetRootModel(this); + + // If model has a collider mesh set, add it to the container + if(modelNode.HasColliderMesh()) { - if(mLights[i]) - { - AddLightRecursively(modelNode, mLights[i], i); - } + RegisterColliderMesh(modelNode); + Scene3D::ColliderMeshProcessor::Get().ColliderMeshChanged(Scene3D::Model::DownCast(Self())); } if(Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE)) @@ -317,18 +340,38 @@ void Model::AddModelNode(Scene3D::ModelNode modelNode) } } +void Model::RegisterColliderMesh(Scene3D::ModelNode& modelNode) +{ + mColliderMeshes[modelNode.GetProperty(Actor::Property::ID)] = modelNode; + + // Add processor + Scene3D::ColliderMeshProcessor::Get().ColliderMeshChanged(Scene3D::Model::DownCast(Self())); +} + +void Model::RemoveColliderMesh(Scene3D::ModelNode& node) +{ + auto id = node.GetProperty(Actor::Property::ID); + auto iter = std::find_if(mColliderMeshes.begin(), mColliderMeshes.end(), [id](auto& item) { + return item.first == id; + }); + if(iter != mColliderMeshes.end()) + { + mColliderMeshes.erase(iter); + } +} + void Model::RemoveModelNode(Scene3D::ModelNode modelNode) { + // remove collider mesh from the list if node is being removed + if(modelNode.HasColliderMesh()) + { + RemoveColliderMesh(modelNode); + GetImplementation(modelNode).SetRootModel(nullptr); + } + if(mModelRoot) { - uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount(); - for(uint32_t i = 0; i < maxLightCount; ++i) - { - if(mLights[i]) - { - RemoveLightRecursively(modelNode, i); - } - } + UpdateShaderRecursively(modelNode, nullptr); mModelRoot.Remove(modelNode); } } @@ -415,6 +458,9 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s mDiffuseTexture.Reset(); mSpecularTexture.Reset(); UpdateImageBasedLightTexture(); + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); } else { @@ -424,6 +470,9 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete)); Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask); mIblDiffuseDirty = false; + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); } if(isOnScene && mIblSpecularDirty) @@ -432,6 +481,9 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete)); Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask); mIblSpecularDirty = false; + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); } } @@ -760,6 +812,29 @@ void Model::SetMotionData(Scene3D::MotionData motionData) } } +void Model::CastShadow(bool castShadow) +{ + mIsShadowCasting = castShadow; + UpdateCastShadowRecursively(mModelRoot, mIsShadowCasting); +} + +bool Model::IsShadowCasting() const +{ + return mIsShadowCasting; +} + +void Model::ReceiveShadow(bool receiveShadow) +{ + mIsShadowReceiving = receiveShadow; + UpdateReceiveShadowRecursively(mModelRoot, mIsShadowReceiving); +} + +bool Model::IsShadowReceiving() const +{ + return mIsShadowReceiving; +} + + /////////////////////////////////////////////////////////// // // Private methods @@ -769,11 +844,43 @@ void Model::OnInitialize() { // Make ParentOrigin as Center. Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); - mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount()); + + mDefaultDiffuseTexture = ImageResourceLoader::GetEmptyTextureWhiteRGB(); + mDefaultSpecularTexture = ImageResourceLoader::GetEmptyTextureWhiteRGB(); } void Model::OnSceneConnection(int depth) { + Actor parent = Self().GetParent(); + while(parent) + { + // If this Model has parent SceneView and the its ShaderManager is same with privious ShaderManager, + // this Model don't need to update shader. + Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent); + if(sceneView) + { + mParentSceneView = sceneView; + GetImpl(sceneView).RegisterSceneItem(this); + Scene3D::Loader::ShaderManagerPtr shaderManager = GetImpl(sceneView).GetShaderManager(); + if(mShaderManager != shaderManager) + { + mShaderManager = shaderManager; + UpdateShaderRecursively(mModelRoot, mShaderManager); + } + break; + } + parent = parent.GetParent(); + } + + // Model can be added on Dali::Scene directly without SceneView. + // So, Model's mShaderManager and shaders of child ModelNodes are needed to be reset when this Model has not parent SceneView. + Scene3D::SceneView parentSceneView = mParentSceneView.GetHandle(); + if(!parentSceneView) + { + mShaderManager = new Dali::Scene3D::Loader::ShaderManager(); + UpdateShaderRecursively(mModelRoot, mShaderManager); + } + if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty()) { // Request model load only if we setup url. @@ -791,19 +898,6 @@ void Model::OnSceneConnection(int depth) SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor); } - Actor parent = Self().GetParent(); - while(parent) - { - Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent); - if(sceneView) - { - GetImpl(sceneView).RegisterSceneItem(this); - mParentSceneView = sceneView; - break; - } - parent = parent.GetParent(); - } - NotifyResourceReady(); mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION)); @@ -813,8 +907,11 @@ void Model::OnSceneConnection(int depth) void Model::OnSceneDisconnection() { + // If mParentSceneView is still onScene, that means this model + // is disconnected from mParentSceneView's sub tree. + // So, Unregister this Model from SceneView. Scene3D::SceneView sceneView = mParentSceneView.GetHandle(); - if(sceneView) + if(sceneView && sceneView.GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE)) { GetImpl(sceneView).UnregisterSceneItem(this); mParentSceneView.Reset(); @@ -910,6 +1007,46 @@ void Model::FitModelPosition() mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot); } +void Model::UpdateCastShadowRecursively(Scene3D::ModelNode node, bool castShadow) +{ + if(!node) + { + return; + } + + GetImplementation(node).CastShadow(castShadow); + uint32_t childrenCount = node.GetChildCount(); + for(uint32_t i = 0; i < childrenCount; ++i) + { + Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i)); + if(!childNode) + { + continue; + } + UpdateCastShadowRecursively(childNode, castShadow); + } +} + +void Model::UpdateReceiveShadowRecursively(Scene3D::ModelNode node, bool receiveShadow) +{ + if(!node) + { + return; + } + + GetImplementation(node).ReceiveShadow(receiveShadow); + uint32_t childrenCount = node.GetChildCount(); + for(uint32_t i = 0; i < childrenCount; ++i) + { + Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i)); + if(!childNode) + { + continue; + } + UpdateReceiveShadowRecursively(childNode, receiveShadow); + } +} + void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels) { if(!node) @@ -1020,6 +1157,15 @@ void Model::ApplyCameraTransform(Dali::CameraActor camera) const camera.SetProperty(Actor::Property::SCALE, resultScale); } +void Model::NotifyShadowMapTexture(Dali::Texture shadowMapTexture) +{ + if(mShadowMapTexture != shadowMapTexture) + { + mShadowMapTexture = shadowMapTexture; + UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture); + } +} + void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels) { if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture) @@ -1045,23 +1191,10 @@ void Model::NotifyImageBasedLightScaleFactor(float scaleFactor) } } -void Model::NotifyLightAdded(uint32_t lightIndex, Scene3D::Light light) -{ - mLights[lightIndex] = light; - AddLightRecursively(mModelRoot, light, lightIndex); -} - -void Model::NotifyLightRemoved(uint32_t lightIndex) -{ - if(mLights[lightIndex]) - { - RemoveLightRecursively(mModelRoot, lightIndex); - mLights[lightIndex].Reset(); - } -} - void Model::OnModelLoadComplete() { + IntrusivePtr self = this; // Keep reference until this API finished + if(!mModelLoadTask->HasSucceeded()) { ResetResourceTasks(); @@ -1086,26 +1219,27 @@ void Model::OnModelLoadComplete() ResetCameraParameters(); if(!resources.mEnvironmentMaps.empty()) { - mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse; - mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular; - } - - uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount(); - for(uint32_t i = 0; i < maxLightCount; ++i) - { - if(mLights[i]) + if(resources.mEnvironmentMaps.front().second.mDiffuse) { - AddLightRecursively(mModelRoot, mLights[i], i); + mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse; + } + if(resources.mEnvironmentMaps.front().second.mSpecular) + { + mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular; } } + if(mShadowMapTexture) + { + UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture); + } UpdateImageBasedLightTexture(); UpdateImageBasedLightScaleFactor(); Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z)); mModelResourceReady = true; - NotifyResourceReady(); ResetResourceTask(mModelLoadTask); + NotifyResourceReady(); } void Model::OnIblDiffuseLoadComplete() @@ -1153,16 +1287,6 @@ void Model::ResetResourceTasks() ResetResourceTask(mIblSpecularLoadTask); } -void Model::ResetResourceTask(IntrusivePtr asyncTask) -{ - if(!asyncTask) - { - return; - } - Dali::AsyncTaskManager::Get().RemoveTask(asyncTask); - asyncTask.Reset(); -} - void Model::NotifyResourceReady() { if(!IsResourceReady()) @@ -1174,12 +1298,13 @@ void Model::NotifyResourceReady() void Model::CreateModel() { - BoundingVolume AABB; - auto& resources = mModelLoadTask->GetResources(); - auto& scene = mModelLoadTask->GetScene(); - auto& resourceChoices = mModelLoadTask->GetResourceChoices(); - Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}}; - Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, {}, {}, {}}; + BoundingVolume AABB; + auto& resources = mModelLoadTask->GetResources(); + auto& scene = mModelLoadTask->GetScene(); + auto& resourceChoices = mModelLoadTask->GetResourceChoices(); + Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}}; + + Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, mShaderManager, {}, {}, {}}; // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly. resources.GenerateResources();