From: seungho baek Date: Mon, 20 Feb 2023 06:57:09 +0000 (+0900) Subject: [Tizen] Generate Camera from loaded model X-Git-Tag: accepted/tizen/7.0/unified/20230302.015546^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1adf92e8aa7004f735a9da1629df8c248a3db990;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git [Tizen] Generate Camera from loaded model This is a combination of 2 commits. Refactoring model-impl.cpp - Extract some method to reduce duplicated code. - Reduce braces depth - Use return early for easy understanding - Separate too long method Generate Camera from loaded model Add API to generete (or apply) the camera what 3D model has. Note that model cannot have ownership of camera since we have to add camera into SceneView or whatever we want. So GenerateCamera create new CameraActor everytime. Or ApplyCamera into already created CameraActor. TODO : Should we change all Scene3D::Loader used demo who use camera parameter? Change-Id: I3900090fc52487c03ce9c66bfc79b31ae8b9e27e Signed-off-by: Eunki Hong --- diff --git a/automated-tests/resources/AnimatedCube.gltf b/automated-tests/resources/AnimatedCube.gltf index 7787c04..807c07e 100644 --- a/automated-tests/resources/AnimatedCube.gltf +++ b/automated-tests/resources/AnimatedCube.gltf @@ -333,7 +333,7 @@ "camera" : 1, "translation" : [ 0.5, 0.5, 3.0 ], "children": [ - 4 + 4, 5, 6, 7 ] }, { @@ -356,6 +356,18 @@ 0.0, 1.0 ] + }, + { + "camera" : 3, + "translation" : [ 0.0, 0.0, 0.0 ] + }, + { + "camera" : 4, + "translation" : [ 0.0, 0.0, 0.0 ] + }, + { + "camera" : 5, + "translation" : [ 0.0, 0.0, 0.0 ] } ], "scene" : 0, @@ -403,6 +415,30 @@ "zfar": 100.0, "znear": 0.01 } + }, + { + "type": "perspective", + "perspective": { + "aspectRatio": 1.0, + "yfov": 0.7, + "znear": 0.01 + } + }, + { + "type": "perspective", + "perspective": { + "aspectRatio": 1.0, + "zfar": 100.0, + "znear": 0.01 + } + }, + { + "type": "orthographic", + "orthographic": { + "xmag": 1.0, + "ymag": 1.0, + "znear": 0.01 + } } ], "samplers": [ diff --git a/automated-tests/src/dali-scene3d/utc-Dali-CameraParameters.cpp b/automated-tests/src/dali-scene3d/utc-Dali-CameraParameters.cpp index 5fec8f2..83f345c 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-CameraParameters.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-CameraParameters.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -35,7 +35,7 @@ int UtcDaliCameraParameters(void) Vector3::ZAXIS * -100.f); camParams.orthographicSize = 3.0f; camParams.aspectRatio = 1.0f; - camParams.yFov = Degree(Radian(M_PI * .5)).degree; + camParams.yFovDegree = Degree(Radian(M_PI * .5)); camParams.zNear = 1.f; camParams.zFar = 1000.f; @@ -70,7 +70,7 @@ int UtcDaliCameraParameters(void) if(camParams.isPerspective) { - DALI_TEST_EQUAL(camera.GetProperty(Dali::CameraActor::Property::FIELD_OF_VIEW).Get(), Radian(Degree(camParams.yFov)).radian); + DALI_TEST_EQUAL(camera.GetProperty(Dali::CameraActor::Property::FIELD_OF_VIEW).Get(), Radian(camParams.yFovDegree).radian); } else { diff --git a/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp b/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp index 357d2a8..e788a5f 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp @@ -180,7 +180,7 @@ int UtcDaliGltfLoaderSuccess1(void) LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCube.gltf", sdf, ctx.loadResult); DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size()); - DALI_TEST_EQUAL(6u, ctx.scene.GetNodeCount()); + DALI_TEST_EQUAL(9u, ctx.scene.GetNodeCount()); // Default envmap is used DALI_TEST_EQUAL(1u, ctx.resources.mEnvironmentMaps.size()); @@ -453,7 +453,7 @@ int UtcDaliGltfLoaderSuccess1(void) DALI_TEST_EQUAL(2u, ctx.resources.mShaders.size()); DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size()); - DALI_TEST_EQUAL(3u, ctx.cameras.size()); + DALI_TEST_EQUAL(6u, ctx.cameras.size()); DALI_TEST_EQUAL(0u, ctx.lights.size()); DALI_TEST_EQUAL(1u, ctx.animations.size()); DALI_TEST_EQUAL(0u, ctx.animationGroups.size()); diff --git a/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp b/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp index 5d2c344..18bd46c 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-Model.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -26,6 +26,8 @@ #include +#include + using namespace Dali; using namespace Dali::Toolkit; @@ -58,7 +60,7 @@ const char* TEST_DLI_EXERCISE_FILE_NAME = TEST_RESOURCE_DIR "/exercis * These textures are based off version of Wave engine sample * Take from https://github.com/WaveEngine/Samples * - * Copyright (c) 2022 Wave Coorporation + * Copyright (c) 2023 Wave Coorporation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -1035,6 +1037,114 @@ int UtcDaliModelAnimation03(void) END_TEST; } +int UtcDaliModelCameraGenerate01(void) +{ + ToolkitTestApplication application; + + Scene3D::Model model = Scene3D::Model::New(TEST_DLI_EXERCISE_FILE_NAME); + model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50)); + application.GetScene().Add(model); + + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + + uint32_t cameraCount = model.GetCameraCount(); + DALI_TEST_EQUALS(1, cameraCount, TEST_LOCATION); + + CameraActor generatedCamera = model.GenerateCamera(0u); + DALI_TEST_CHECK(generatedCamera); + + generatedCamera = model.GenerateCamera(1u); // Fail to generate camera + DALI_TEST_CHECK(!generatedCamera); + + END_TEST; +} + +int UtcDaliModelCameraGenerate02(void) +{ + ToolkitTestApplication application; + + Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME); + model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50)); + application.GetScene().Add(model); + + gResourceReadyCalled = false; + model.ResourceReadySignal().Connect(&OnResourceReady); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION); + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + + uint32_t cameraCount = model.GetCameraCount(); + DALI_TEST_EQUALS(6, cameraCount, TEST_LOCATION); + + CameraActor generatedCamera0 = model.GenerateCamera(0u); + DALI_TEST_CHECK(generatedCamera0); + CameraActor generatedCamera1 = model.GenerateCamera(1u); + DALI_TEST_CHECK(generatedCamera1); + CameraActor generatedCamera2 = model.GenerateCamera(2u); + DALI_TEST_CHECK(generatedCamera2); + CameraActor generatedCamera3 = model.GenerateCamera(3u); // Infinity far camera + DALI_TEST_CHECK(generatedCamera3); + CameraActor generatedCamera4 = model.GenerateCamera(4u); // Broken camera 1 + DALI_TEST_CHECK(!generatedCamera4); + CameraActor generatedCamera5 = model.GenerateCamera(5u); // Broken camera 2 + DALI_TEST_CHECK(!generatedCamera5); + CameraActor generatedCamera6 = model.GenerateCamera(6u); // Out of bound + DALI_TEST_CHECK(!generatedCamera6); + + CameraActor appliedCamera; + DALI_TEST_EQUALS(model.ApplyCamera(0u, appliedCamera), false, TEST_LOCATION); // Cannot apply into empty camera. + + auto CompareCameraProperties = [](CameraActor lhs, CameraActor rhs, const char* location) { + DALI_TEST_EQUALS(lhs.GetProperty(Dali::CameraActor::Property::PROJECTION_MODE), rhs.GetProperty(Dali::CameraActor::Property::PROJECTION_MODE), TEST_LOCATION); + DALI_TEST_EQUALS(lhs.GetProperty(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE), rhs.GetProperty(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE), TEST_LOCATION); + + if(lhs.GetProperty(Dali::CameraActor::Property::PROJECTION_MODE) == static_cast(Dali::Camera::ProjectionMode::PERSPECTIVE_PROJECTION)) + { + DALI_TEST_EQUALS(lhs.GetProperty(Dali::CameraActor::Property::FIELD_OF_VIEW), rhs.GetProperty(Dali::CameraActor::Property::FIELD_OF_VIEW), TEST_LOCATION); + // TODO : Open this test when infinity far projection implement. + //DALI_TEST_EQUALS(lhs.GetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE), rhs.GetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE), TEST_LOCATION); + } + else + { + DALI_TEST_EQUALS(lhs.GetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE), rhs.GetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE), TEST_LOCATION); + DALI_TEST_EQUALS(lhs.GetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE), rhs.GetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE), TEST_LOCATION); + } + }; + + appliedCamera = CameraActor::New(); + DALI_TEST_EQUALS(model.ApplyCamera(0u, appliedCamera), true, TEST_LOCATION); + CompareCameraProperties(generatedCamera0, appliedCamera, TEST_LOCATION); + DALI_TEST_EQUALS(model.ApplyCamera(1u, appliedCamera), true, TEST_LOCATION); + CompareCameraProperties(generatedCamera1, appliedCamera, TEST_LOCATION); + DALI_TEST_EQUALS(model.ApplyCamera(2u, appliedCamera), true, TEST_LOCATION); + CompareCameraProperties(generatedCamera2, appliedCamera, TEST_LOCATION); + DALI_TEST_EQUALS(model.ApplyCamera(3u, appliedCamera), true, TEST_LOCATION); + CompareCameraProperties(generatedCamera3, appliedCamera, TEST_LOCATION); + DALI_TEST_EQUALS(model.ApplyCamera(4u, appliedCamera), false, TEST_LOCATION); // Broken camera 1 + DALI_TEST_EQUALS(model.ApplyCamera(5u, appliedCamera), false, TEST_LOCATION); // Broken camera 2 + DALI_TEST_EQUALS(model.ApplyCamera(6u, appliedCamera), false, TEST_LOCATION); // Cannot apply over the index. + + END_TEST; +} + int UtcDaliModelMultiplePrimitives(void) { ToolkitTestApplication application; @@ -1082,8 +1192,8 @@ int UtcDaliModelColorMode(void) application.SendNotification(); application.Render(); - Actor actor = model.FindChildByName("AnimatedCube"); - Vector4 childColor = actor[Dali::Actor::Property::COLOR]; + Actor actor = model.FindChildByName("AnimatedCube"); + Vector4 childColor = actor[Dali::Actor::Property::COLOR]; Vector4 childWorldColor = actor[Dali::Actor::Property::WORLD_COLOR]; DALI_TEST_EQUALS(childColor, Color::WHITE, TEST_LOCATION); diff --git a/dali-scene3d/internal/common/environment-map-load-task.cpp b/dali-scene3d/internal/common/environment-map-load-task.cpp index d230e99..d847f46 100644 --- a/dali-scene3d/internal/common/environment-map-load-task.cpp +++ b/dali-scene3d/internal/common/environment-map-load-task.cpp @@ -58,9 +58,9 @@ bool EnvironmentMapLoadTask::HasSucceeded() const return mHasSucceeded; } -Dali::Scene3D::Loader::EnvironmentMapData& EnvironmentMapLoadTask::GetEnvironmentMap() +Dali::Texture EnvironmentMapLoadTask::GetLoadedTexture() { - return mEnvironmentMapData; + return (HasSucceeded()) ? mEnvironmentMapData.GetTexture() : Texture();; } } // namespace Internal diff --git a/dali-scene3d/internal/common/environment-map-load-task.h b/dali-scene3d/internal/common/environment-map-load-task.h index d9a936b..446665c 100644 --- a/dali-scene3d/internal/common/environment-map-load-task.h +++ b/dali-scene3d/internal/common/environment-map-load-task.h @@ -71,10 +71,11 @@ public: bool HasSucceeded() const; /** - * Retrieves loaded Environment Map - * @return EnvironmentMapData that is loaded from url. + * Retrieves loaded Ibl Texture + * @return Texture that is loaded from url. + * @note Do not call this method in worker thread. */ - Dali::Scene3D::Loader::EnvironmentMapData& GetEnvironmentMap(); + Dali::Texture GetLoadedTexture(); private: // Undefined diff --git a/dali-scene3d/internal/controls/model/model-impl.cpp b/dali-scene3d/internal/controls/model/model-impl.cpp index 3345bfc..e5d5e78 100644 --- a/dali-scene3d/internal/controls/model/model-impl.cpp +++ b/dali-scene3d/internal/controls/model/model-impl.cpp @@ -23,11 +23,11 @@ #include #include #include +#include #include #include #include #include -#include #include // INTERNAL INCLUDES @@ -251,13 +251,13 @@ bool Model::GetChildrenFocusable() const void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor) { bool needIblReset = false; - bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); + bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); if(mDiffuseIblUrl != diffuseUrl) { mDiffuseIblUrl = diffuseUrl; if(mDiffuseIblUrl.empty()) { - needIblReset = true; + needIblReset = true; } else { @@ -271,7 +271,7 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s mSpecularIblUrl = specularUrl; if(mSpecularIblUrl.empty()) { - needIblReset = true; + needIblReset = true; } else { @@ -284,17 +284,8 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s // we don't need to request to load texture. if(needIblReset) { - if(mIblDiffuseLoadTask) - { - Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); - mIblDiffuseLoadTask.Reset(); - } - - if(mIblSpecularLoadTask) - { - Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); - mIblSpecularLoadTask.Reset(); - } + ResetResourceTask(mIblDiffuseLoadTask); + ResetResourceTask(mIblSpecularLoadTask); mIblDiffuseDirty = false; mIblSpecularDirty = false; @@ -309,11 +300,7 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s { if(isOnScene && mIblDiffuseDirty) { - if(mIblDiffuseLoadTask) - { - Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); - mIblDiffuseLoadTask.Reset(); - } + ResetResourceTask(mIblDiffuseLoadTask); mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete)); Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask); mIblDiffuseDirty = false; @@ -321,11 +308,7 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s if(isOnScene && mIblSpecularDirty) { - if(mIblSpecularLoadTask) - { - Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); - mIblSpecularLoadTask.Reset(); - } + ResetResourceTask(mIblSpecularLoadTask); mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete)); Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask); mIblSpecularDirty = false; @@ -339,10 +322,7 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s } // If diffuse and specular textures are already loaded, emits resource ready signal here. - if(IsResourceReady()) - { - Control::SetResourceReady(false); - } + NotifyResourceReady(); } void Model::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor) @@ -403,6 +383,45 @@ Dali::Animation Model::GetAnimation(const std::string& name) const return animation; } +uint32_t Model::GetCameraCount() const +{ + return mCameraParameters.size(); +} + +Dali::CameraActor Model::GenerateCamera(uint32_t index) const +{ + Dali::CameraActor camera; + if(mCameraParameters.size() > index) + { + camera = Dali::CameraActor::New3DCamera(); + if(!mCameraParameters[index].ConfigureCamera(camera, false)) + { + DALI_LOG_ERROR("Fail to generate %u's camera actor : Some property was not defined. Please check model file.\n", index); + camera.Reset(); + return camera; + } + + ApplyCameraTransform(camera); + } + return camera; +} + +bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const +{ + if(camera && mCameraParameters.size() > index) + { + if(!mCameraParameters[index].ConfigureCamera(camera, false)) + { + DALI_LOG_ERROR("Fail to apply %u's camera actor : Some property was not defined. Please check model file.\n", index); + return false; + } + + ApplyCameraTransform(camera); + return true; + } + return false; +} + /////////////////////////////////////////////////////////// // // Private methods @@ -493,30 +512,33 @@ bool Model::IsResourceReady() const void Model::ScaleModel() { - if(mModelRoot) + if(!mModelRoot) { - float scale = 1.0f; - Vector3 size = Self().GetProperty(Dali::Actor::Property::SIZE); - if(size.x > 0.0f && size.y > 0.0f) - { - scale = MAXFLOAT; - scale = std::min(size.x / mNaturalSize.x, scale); - scale = std::min(size.y / mNaturalSize.y, scale); - } - // Models in glTF and dli are defined as right hand coordinate system. - // DALi uses left hand coordinate system. Scaling negative is for change winding order. - mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale); + return; + } + + float scale = 1.0f; + Vector3 size = Self().GetProperty(Dali::Actor::Property::SIZE); + if(size.x > 0.0f && size.y > 0.0f) + { + scale = MAXFLOAT; + scale = std::min(size.x / mNaturalSize.x, scale); + scale = std::min(size.y / mNaturalSize.y, scale); } + // Models in glTF and dli are defined as right hand coordinate system. + // DALi uses left hand coordinate system. Scaling negative is for change winding order. + mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale); } void Model::FitModelPosition() { - if(mModelRoot) + if(!mModelRoot) { - // Loaded model pivot is not the model center. - mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); - mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot); + return; } + // Loaded model pivot is not the model center. + mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot); } void Model::CollectRenderableActor(Actor actor) @@ -550,29 +572,33 @@ void Model::UpdateImageBasedLightTexture() for(auto&& actor : mRenderableActors) { Actor renderableActor = actor.GetHandle(); - if(renderableActor) + if(!renderableActor) + { + continue; + } + + uint32_t rendererCount = renderableActor.GetRendererCount(); + for(uint32_t i = 0; i < rendererCount; ++i) { - uint32_t rendererCount = renderableActor.GetRendererCount(); - for(uint32_t i = 0; i < rendererCount; ++i) + Dali::Renderer renderer = renderableActor.GetRendererAt(i); + if(!renderer) { - Dali::Renderer renderer = renderableActor.GetRendererAt(i); - if(renderer) - { - Dali::TextureSet textures = renderer.GetTextures(); - if(textures) - { - uint32_t textureCount = textures.GetTextureCount(); - // EnvMap requires at least 2 texture, diffuse and specular - if(textureCount > 2u) - { - textures.SetTexture(textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE, currentDiffuseTexture); - textures.SetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE, currentSpecularTexture); - } - } - } + continue; + } + Dali::TextureSet textures = renderer.GetTextures(); + if(!textures) + { + continue; + } + uint32_t textureCount = textures.GetTextureCount(); + // EnvMap requires at least 2 texture, diffuse and specular + if(textureCount > 2u) + { + textures.SetTexture(textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE, currentDiffuseTexture); + textures.SetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE, currentSpecularTexture); } - renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor); } + renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor); } } @@ -595,6 +621,45 @@ void Model::UpdateImageBasedLightScaleFactor() } } +void Model::ApplyCameraTransform(Dali::CameraActor camera) const +{ + Vector3 selfPosition = Self().GetProperty(Actor::Property::POSITION); + Quaternion selfOrientation = Self().GetProperty(Actor::Property::ORIENTATION); + Vector3 selfScale = Self().GetProperty(Actor::Property::SCALE); + + Vector3 cameraPosition = camera.GetProperty(Actor::Property::POSITION); + Quaternion cameraOrientation = camera.GetProperty(Actor::Property::ORIENTATION); + Vector3 cameraScale = camera.GetProperty(Actor::Property::SCALE); + + // Models in glTF and dli are defined as right hand coordinate system. + // DALi uses left hand coordinate system. Scaling negative is for change winding order. + if(!Dali::Equals(Y_DIRECTION.Dot(Vector3::YAXIS), 1.0f)) + { + // Reflect by XZ plane + cameraPosition.y = -cameraPosition.y; + Quaternion yDirectionQuaternion; + yDirectionQuaternion.mVector = Vector3::YAXIS; + // Reflect orientation + cameraOrientation = yDirectionQuaternion * cameraOrientation * yDirectionQuaternion; + } + + Vector3 resultPosition; + Quaternion resultOrientation; + Vector3 resultScale; + + Matrix selfMatrix(false); + Matrix cameraMatrix(false); + Matrix resultMatrix(false); + selfMatrix.SetTransformComponents(selfScale, selfOrientation, selfPosition); + cameraMatrix.SetTransformComponents(cameraScale, cameraOrientation, cameraPosition); + Matrix::Multiply(resultMatrix, cameraMatrix, selfMatrix); + resultMatrix.GetTransformComponents(resultPosition, resultOrientation, resultScale); + + camera.SetProperty(Actor::Property::POSITION, resultPosition); + camera.SetProperty(Actor::Property::ORIENTATION, resultOrientation); + camera.SetProperty(Actor::Property::SCALE, resultScale); +} + void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor) { if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture) @@ -627,33 +692,14 @@ void Model::OnModelLoadComplete() return; } - mModelRoot = Actor::New(); - mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR); - - BoundingVolume AABB; - auto* resources = &(mModelLoadTask->mResources); - auto* scene = &(mModelLoadTask->mScene); - Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}}; - Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{*resources, xforms, {}, {}, {}}; - uint32_t rootCount = 0u; - for(auto iRoot : scene->GetRoots()) - { - resources->GenerateResources(mModelLoadTask->mResourceRefCounts[rootCount]); - - if(auto actor = scene->CreateNodes(iRoot, mModelLoadTask->mResourceChoices, nodeParams)) - { - scene->ConfigureSkeletonJoints(iRoot, resources->mSkeletons, actor); - scene->ConfigureSkinningShaders(*resources, actor, std::move(nodeParams.mSkinnables)); - ConfigureBlendShapeShaders(*resources, *scene, actor, std::move(nodeParams.mBlendshapeRequests)); - - scene->ApplyConstraints(actor, std::move(nodeParams.mConstrainables)); - - mModelRoot.Add(actor); - } + CreateModel(); + mRenderableActors.clear(); + CollectRenderableActor(mModelRoot); - AddModelTreeToAABB(AABB, *scene, mModelLoadTask->mResourceChoices, iRoot, nodeParams, Matrix::IDENTITY); - rootCount++; - } + auto* resources = &(mModelLoadTask->mResources); + auto* scene = &(mModelLoadTask->mScene); + CreateAnimations(*scene); + ResetCameraParameters(); if(!resources->mEnvironmentMaps.empty()) { @@ -661,124 +707,157 @@ void Model::OnModelLoadComplete() mDefaultSpecularTexture = resources->mEnvironmentMaps.front().second.mSpecular; } - if(!mModelLoadTask->mAnimations.empty()) - { - auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) - { - Dali::Actor actor; - if(property.mNodeIndex != Scene3D::Loader::INVALID_INDEX) - { - auto* node = scene->GetNode(property.mNodeIndex); - if(node != nullptr) - { - actor = mModelRoot.FindChildById(node->mNodeId); - } - } - else - { - actor = mModelRoot.FindChildByName(property.mNodeName); - } - return actor; - }; - - mAnimations.clear(); - for(auto&& animation : mModelLoadTask->mAnimations) - { - Dali::Animation anim = animation.ReAnimate(getActor); - - mAnimations.push_back({animation.mName, anim}); - } - } - - mRenderableActors.clear(); - CollectRenderableActor(mModelRoot); - UpdateImageBasedLightTexture(); UpdateImageBasedLightScaleFactor(); - mNaturalSize = AABB.CalculateSize(); - mModelPivot = AABB.CalculatePivot(); - mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize); - Vector3 controlSize = Self().GetProperty(Dali::Actor::Property::SIZE); - if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y)) - { - Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize); - } - - FitModelPosition(); - ScaleModel(); - mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive); mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable); mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable); Self().Add(mModelRoot); - Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z)); mModelResourceReady = true; - - if(IsResourceReady()) - { - Control::SetResourceReady(false); - } - mModelLoadTask.Reset(); + NotifyResourceReady(); + ResetResourceTask(mModelLoadTask); } void Model::OnIblDiffuseLoadComplete() { - mDiffuseTexture = (mIblDiffuseLoadTask->HasSucceeded()) ? mIblDiffuseLoadTask->GetEnvironmentMap().GetTexture() : Texture(); + mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture(); + ResetResourceTask(mIblDiffuseLoadTask); mIblDiffuseResourceReady = true; if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { OnIblLoadComplete(); } - mIblDiffuseLoadTask.Reset(); } void Model::OnIblSpecularLoadComplete() { - mSpecularTexture = (mIblSpecularLoadTask->HasSucceeded()) ? mIblSpecularLoadTask->GetEnvironmentMap().GetTexture() : Texture(); + mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture(); + ResetResourceTask(mIblSpecularLoadTask); mIblSpecularResourceReady = true; if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { OnIblLoadComplete(); } - mIblSpecularLoadTask.Reset(); } void Model::OnIblLoadComplete() { UpdateImageBasedLightTexture(); + NotifyResourceReady(); +} - if(IsResourceReady()) +void Model::ResetResourceTasks() +{ + if(!Dali::Adaptor::IsAvailable()) { - Control::SetResourceReady(false); + return; } + ResetResourceTask(mModelLoadTask); + ResetResourceTask(mIblDiffuseLoadTask); + ResetResourceTask(mIblSpecularLoadTask); } -void Model::ResetResourceTasks() +void Model::ResetResourceTask(IntrusivePtr asyncTask) { - if(Dali::Adaptor::IsAvailable()) + if(!asyncTask) { - if(mModelLoadTask) - { - Dali::AsyncTaskManager::Get().RemoveTask(mModelLoadTask); - mModelLoadTask.Reset(); - } - if(mIblDiffuseLoadTask) + return; + } + Dali::AsyncTaskManager::Get().RemoveTask(asyncTask); + asyncTask.Reset(); +} + +void Model::NotifyResourceReady() +{ + if(!IsResourceReady()) + { + return; + } + Control::SetResourceReady(false); +} + +void Model::CreateModel() +{ + mModelRoot = Actor::New(); + mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR); + + BoundingVolume AABB; + auto* resources = &(mModelLoadTask->mResources); + auto* scene = &(mModelLoadTask->mScene); + Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}}; + Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{*resources, xforms, {}, {}, {}}; + uint32_t rootCount = 0u; + for(auto iRoot : scene->GetRoots()) + { + resources->GenerateResources(mModelLoadTask->mResourceRefCounts[rootCount]); + + if(auto actor = scene->CreateNodes(iRoot, mModelLoadTask->mResourceChoices, nodeParams)) { - Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask); - mIblDiffuseLoadTask.Reset(); + scene->ConfigureSkeletonJoints(iRoot, resources->mSkeletons, actor); + scene->ConfigureSkinningShaders(*resources, actor, std::move(nodeParams.mSkinnables)); + ConfigureBlendShapeShaders(*resources, *scene, actor, std::move(nodeParams.mBlendshapeRequests)); + + scene->ApplyConstraints(actor, std::move(nodeParams.mConstrainables)); + + mModelRoot.Add(actor); } - if(mIblSpecularLoadTask) + + AddModelTreeToAABB(AABB, *scene, mModelLoadTask->mResourceChoices, iRoot, nodeParams, Matrix::IDENTITY); + rootCount++; + } + + mNaturalSize = AABB.CalculateSize(); + mModelPivot = AABB.CalculatePivot(); + mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize); + Vector3 controlSize = Self().GetProperty(Dali::Actor::Property::SIZE); + if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y)) + { + Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize); + } + FitModelPosition(); + ScaleModel(); +} + +void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene) +{ + mAnimations.clear(); + if(!mModelLoadTask->mAnimations.empty()) + { + auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) { + if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX) + { + return mModelRoot.FindChildByName(property.mNodeName); + } + auto* node = scene.GetNode(property.mNodeIndex); + if(node == nullptr) + { + return Dali::Actor(); + } + return mModelRoot.FindChildById(node->mNodeId); + }; + + for(auto&& animation : mModelLoadTask->mAnimations) { - Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask); - mIblSpecularLoadTask.Reset(); + Dali::Animation anim = animation.ReAnimate(getActor); + mAnimations.push_back({animation.mName, anim}); } } } +void Model::ResetCameraParameters() +{ + mCameraParameters.clear(); + if(!mModelLoadTask->mCameraParameters.empty()) + { + // Copy camera parameters. + std::copy(mModelLoadTask->mCameraParameters.begin(), mModelLoadTask->mCameraParameters.end(), std::back_inserter(mCameraParameters)); + } +} + } // namespace Internal } // namespace Scene3D } // namespace Dali diff --git a/dali-scene3d/internal/controls/model/model-impl.h b/dali-scene3d/internal/controls/model/model-impl.h index e4f1f08..fea5d60 100644 --- a/dali-scene3d/internal/controls/model/model-impl.h +++ b/dali-scene3d/internal/controls/model/model-impl.h @@ -2,7 +2,7 @@ #define DALI_SCENE3D_INTERNAL_MODEL_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include +#include #include #include #include @@ -47,6 +48,7 @@ class Model : public Dali::Toolkit::Internal::Control, public ImageBasedLightObs { public: using AnimationData = std::pair; + using CameraData = Loader::CameraParameters; /** * @brief Creates a new Model. @@ -115,6 +117,21 @@ public: */ Dali::Animation GetAnimation(const std::string& name) const; + /** + * @copydoc Model::GetCameraCount() + */ + uint32_t GetCameraCount() const; + + /** + * @copydoc Model::GenerateCamera() + */ + Dali::CameraActor GenerateCamera(uint32_t index) const; + + /** + * @copydoc Model::ApplyCamera() + */ + bool ApplyCamera(uint32_t index, Dali::CameraActor camera) const; + protected: /** * @brief Constructs a new Model. @@ -167,6 +184,7 @@ private: */ bool IsResourceReady() const override; +private: /** * @brief Scales the model to fit the control or to return to original size. */ @@ -192,6 +210,15 @@ private: */ void UpdateImageBasedLightScaleFactor(); + /** + * @brief Apply self transform into inputed camera. + * Inputed camera must be configured by CameraParameter. Mean, inputed camera coordinate depend on Model. + * After this API finished, CameraActor coordinate system converted as DALi coordinate system. + * + * @param[in,out] camera CameraActor who need to apply model itself's transform + */ + void ApplyCameraTransform(Dali::CameraActor camera) const; + public: // Overrides ImageBasedLightObserver Methods. /** * @copydoc Dali::Scene3D::Internal::ImageBasedLightObserver::NotifyImageBasedLightTexture() @@ -229,11 +256,42 @@ private: */ void ResetResourceTasks(); + /** + * @brief Reset a Resource loading task. + */ + void ResetResourceTask(IntrusivePtr asyncTask); + + /** + * @brief Request to load a Ibl texture asynchronously + */ + void RequestLoadIblTexture(EnvironmentMapLoadTaskPtr asyncLoadTask, const std::string& url); + + /** + * @brief Notify Resource Ready signal. + */ + void NotifyResourceReady(); + + /** + * @brief Create Model from loaded SceneDefinition. + */ + void CreateModel(); + + /** + * @brief Create Dali::Animation from loaded AnimationDefinitions. + */ + void CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene); + + /** + * @brief Reset CameraData from loaded CameraParameters. + */ + void ResetCameraParameters(); + private: std::string mModelUrl; std::string mResourceDirectoryUrl; Dali::Actor mModelRoot; std::vector mAnimations; + std::vector mCameraParameters; std::vector> mRenderableActors; WeakHandle mParentSceneView; diff --git a/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp index 1c4a9a8..a4158e1 100644 --- a/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp +++ b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp @@ -789,7 +789,7 @@ void SceneView::OnSkyboxLoadComplete() Control::SetResourceReady(false); } - mSkyboxTexture = (mSkyboxLoadTask->HasSucceeded()) ? mSkyboxLoadTask->GetEnvironmentMap().GetTexture() : Texture(); + mSkyboxTexture = mSkyboxLoadTask->GetLoadedTexture(); Shader skyboxShader; if(mSkyboxEnvironmentMapType == Scene3D::EnvironmentMapType::CUBEMAP) { @@ -814,7 +814,7 @@ void SceneView::OnSkyboxLoadComplete() void SceneView::OnIblDiffuseLoadComplete() { - mDiffuseTexture = (mIblDiffuseLoadTask->HasSucceeded()) ? mIblDiffuseLoadTask->GetEnvironmentMap().GetTexture() : Texture(); + mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture(); mIblDiffuseResourceReady = true; if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { @@ -825,7 +825,7 @@ void SceneView::OnIblDiffuseLoadComplete() void SceneView::OnIblSpecularLoadComplete() { - mSpecularTexture = (mIblSpecularLoadTask->HasSucceeded()) ? mIblSpecularLoadTask->GetEnvironmentMap().GetTexture() : Texture(); + mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture(); mIblSpecularResourceReady = true; if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { diff --git a/dali-scene3d/internal/loader/gltf2-asset.h b/dali-scene3d/internal/loader/gltf2-asset.h index 2a1392a..6576803 100644 --- a/dali-scene3d/internal/loader/gltf2-asset.h +++ b/dali-scene3d/internal/loader/gltf2-asset.h @@ -1,7 +1,7 @@ #ifndef DALI_SCENE3D_LOADER_GLTF2_ASSET_H_ #define DALI_SCENE3D_LOADER_GLTF2_ASSET_H_ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -18,16 +18,16 @@ */ // INTERNAL INCLUDES -#include "dali-scene3d/internal/loader/json-reader.h" -#include "dali-scene3d/public-api/loader/index.h" +#include +#include // EXTERNAL INCLUDES +#include +#include +#include +#include #include #include -#include "dali/devel-api/common/map-wrapper.h" -#include "dali/public-api/common/vector-wrapper.h" -#include "dali/public-api/math/quaternion.h" -#include "dali/public-api/math/vector4.h" #define ENUM_STRING_MAPPING(t, x) \ { \ @@ -50,7 +50,8 @@ namespace gltf2 { -using Index = Dali::Scene3D::Loader::Index; +using Index = Dali::Scene3D::Loader::Index; +constexpr float UNDEFINED_FLOAT_VALUE = -1.0f; ///< Special marker for some non-negative only float values. template class Ref @@ -350,7 +351,7 @@ struct TextureInfo */ struct MaterialIor { - float mIor = MAXFLOAT; + float mIor = UNDEFINED_FLOAT_VALUE; }; /** @@ -446,20 +447,20 @@ struct Camera : Named { struct Perspective { - float mAspectRatio; - float mYFov; - float mZFar; - float mZNear; + float mAspectRatio = UNDEFINED_FLOAT_VALUE; + float mYFov = UNDEFINED_FLOAT_VALUE; + float mZFar = UNDEFINED_FLOAT_VALUE; + float mZNear = UNDEFINED_FLOAT_VALUE; //TODO: extras //TODO: extensions }; struct Orthographic { - float mXMag; - float mYMag; - float mZFar; - float mZNear; + float mXMag = UNDEFINED_FLOAT_VALUE; + float mYMag = UNDEFINED_FLOAT_VALUE; + float mZFar = UNDEFINED_FLOAT_VALUE; + float mZNear = UNDEFINED_FLOAT_VALUE; //TODO: extras //TODO: extensions }; diff --git a/dali-scene3d/public-api/controls/model/model.cpp b/dali-scene3d/public-api/controls/model/model.cpp index c0369ab..fa792f9 100644 --- a/dali-scene3d/public-api/controls/model/model.cpp +++ b/dali-scene3d/public-api/controls/model/model.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -122,6 +122,21 @@ Dali::Animation Model::GetAnimation(const std::string& name) const return GetImpl(*this).GetAnimation(name); } +uint32_t Model::GetCameraCount() const +{ + return GetImpl(*this).GetCameraCount(); +} + +Dali::CameraActor Model::GenerateCamera(uint32_t index) const +{ + return GetImpl(*this).GenerateCamera(index); +} + +bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const +{ + return GetImpl(*this).ApplyCamera(index, camera); +} + } // namespace Scene3D } // namespace Dali diff --git a/dali-scene3d/public-api/controls/model/model.h b/dali-scene3d/public-api/controls/model/model.h index 45ceca1..ce723ea 100644 --- a/dali-scene3d/public-api/controls/model/model.h +++ b/dali-scene3d/public-api/controls/model/model.h @@ -2,7 +2,7 @@ #define DALI_SCENE3D_MODEL_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -23,6 +23,7 @@ // EXTERNAL INCLUDES #include +#include #include #include @@ -270,6 +271,43 @@ public: */ Dali::Animation GetAnimation(const std::string& name) const; + /** + * @brief Gets number of camera parameters those loaded from model file. + * + * @SINCE_2_2.15 + * @return The number of loaded camera parameters. + * @note This method should be called after Model load finished. + */ + uint32_t GetCameraCount() const; + + /** + * @brief Generate camera actor using camera parameters at the index. + * If camera parameter is valid, create new CameraActor. + * Camera parameter decide at initialized time and + * didn't apply model node's current position (like Animation). + * + * @SINCE_2_2.15 + * @param[in] index Index of camera to be used for generation camera. + * @return Generated CameraActor by the index, or empty Handle if generation failed. + * @note This method should be called after Model load finished. + */ + Dali::CameraActor GenerateCamera(uint32_t index) const; + + /** + * @brief Apply camera parameters at the index to inputed camera actor. + * If camera parameter is valid and camera actor is not empty, apply parameters. + * It will change camera's transform and near / far / fov or orthographic size / aspect ratio (if defined) + * Camera parameter decide at initialized time and + * didn't apply model node's current position (like Animation). + * + * @SINCE_2_2.15 + * @param[in] index Index of camera to be used for generation camera. + * @param[in,out] camera Index of camera to be used for generation camera. + * @return True if apply successed. False otherwise. + * @note This method should be called after Model load finished. + */ + bool ApplyCamera(uint32_t index, Dali::CameraActor camera) const; + public: // Not intended for application developers /// @cond internal /** diff --git a/dali-scene3d/public-api/loader/camera-parameters.cpp b/dali-scene3d/public-api/loader/camera-parameters.cpp index 270f84b..cc9a351 100644 --- a/dali-scene3d/public-api/loader/camera-parameters.cpp +++ b/dali-scene3d/public-api/loader/camera-parameters.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -14,12 +14,19 @@ * limitations under the License. * */ -#include "dali-scene3d/public-api/loader/camera-parameters.h" -#include "dali-scene3d/public-api/loader/utils.h" -#include "dali/devel-api/actors/camera-actor-devel.h" -#include "dali/integration-api/debug.h" -#include "dali/public-api/actors/camera-actor.h" -#include "dali/public-api/math/quaternion.h" + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include // for gltf2::UNDEFINED_FLOAT_VALUE +#include namespace Dali { @@ -143,11 +150,12 @@ void Orthographic(Matrix& result, float left, float right, float bottom, float t ViewProjection CameraParameters::GetViewProjection() const { ViewProjection viewProjection; + // The projection matrix. if(isPerspective) { Perspective(viewProjection.GetProjection(), - Radian(Degree(yFov)), + Radian(yFovDegree), 1.f, zNear, zFar, @@ -191,36 +199,75 @@ void CameraParameters::CalculateTransformComponents(Vector3& position, Quaternio orientation *= viewQuaternion; } -void CameraParameters::ConfigureCamera(CameraActor& camera) const +bool CameraParameters::ConfigureCamera(CameraActor& camera, bool invertY) const { - SetActorCentered(camera); - if(isPerspective) { + if(Dali::Equals(zNear, gltf2::UNDEFINED_FLOAT_VALUE) || + Dali::Equals(yFovDegree.degree, gltf2::UNDEFINED_FLOAT_VALUE)) + { + return false; + } + camera.SetProjectionMode(Camera::PERSPECTIVE_PROJECTION); camera.SetNearClippingPlane(zNear); - camera.SetFarClippingPlane(zFar); - camera.SetFieldOfView(Radian(Degree(yFov))); + camera.SetFieldOfView(Radian(yFovDegree)); + + if(!Dali::Equals(zFar, gltf2::UNDEFINED_FLOAT_VALUE)) + { + camera.SetFarClippingPlane(zFar); + } + else + { + // TODO : Infinite perspective projection didn't support yet. Just set big enough value now + camera.SetFarClippingPlane(1000.0f); + } + + if(!Dali::Equals(aspectRatio, gltf2::UNDEFINED_FLOAT_VALUE)) + { + // TODO: By gltf 2.0 spec, we should not 'crop' and 'non-uniform scaling' by viewport. + // If we skip to setup this value, 'non-uniform scaling' problem fixed. + // But we need to resolve 'crop' case in future. + //camera.SetAspectRatio(aspectRatio); + } } else { + if(Dali::Equals(zNear, gltf2::UNDEFINED_FLOAT_VALUE) || + Dali::Equals(zFar, gltf2::UNDEFINED_FLOAT_VALUE) || + Dali::Equals(orthographicSize, gltf2::UNDEFINED_FLOAT_VALUE)) + { + return false; + } + camera.SetProjectionMode(Camera::ORTHOGRAPHIC_PROJECTION); camera.SetNearClippingPlane(zNear); camera.SetFarClippingPlane(zFar); - camera.SetAspectRatio(aspectRatio); camera.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, orthographicSize); + + if(!Dali::Equals(aspectRatio, gltf2::UNDEFINED_FLOAT_VALUE)) + { + // TODO: By gltf 2.0 spec, we should not 'crop' and 'non-uniform scaling' by viewport. + // If we skip to setup this value, 'non-uniform scaling' problem fixed. + // But we need to resolve 'crop' case in future. + //camera.SetAspectRatio(aspectRatio); + } } + SetActorCentered(camera); + // model Vector3 camTranslation; Vector3 camScale; Quaternion camOrientation; CalculateTransformComponents(camTranslation, camOrientation, camScale); - camera.SetInvertYAxis(true); + camera.SetInvertYAxis(invertY); camera.SetProperty(Actor::Property::POSITION, camTranslation); camera.SetProperty(Actor::Property::ORIENTATION, camOrientation); camera.SetProperty(Actor::Property::SCALE, camScale); + + return true; } } // namespace Loader diff --git a/dali-scene3d/public-api/loader/camera-parameters.h b/dali-scene3d/public-api/loader/camera-parameters.h index 70060e5..9fde071 100644 --- a/dali-scene3d/public-api/loader/camera-parameters.h +++ b/dali-scene3d/public-api/loader/camera-parameters.h @@ -1,7 +1,7 @@ #ifndef DALI_SCENE3D_LOADER_CAMERA_PARAMETERS_H #define DALI_SCENE3D_LOADER_CAMERA_PARAMETERS_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -18,12 +18,13 @@ */ // INTERNAL INCLUDES -#include "dali-scene3d/public-api/api.h" -#include "dali-scene3d/public-api/loader/view-projection.h" +#include +#include // EXTERNAL INCLUDES -#include "dali/public-api/math/matrix.h" -#include "dali/public-api/math/vector3.h" +#include +#include +#include namespace Dali { @@ -35,10 +36,11 @@ namespace Loader { struct DALI_SCENE3D_API CameraParameters { + // TODO : Is these default value has is meaning? Matrix matrix = Matrix::IDENTITY; float orthographicSize = 1.f; float aspectRatio = 1.f; - float yFov = 60.f; + Degree yFovDegree = Degree(60.f); float zNear = 0.1f; float zFar = 1000.f; bool isPerspective = true; @@ -58,8 +60,10 @@ struct DALI_SCENE3D_API CameraParameters * @brief Configures the camera in the way that it is supposed to be used with * scene3d scenes. This means inverted Y and a rotation of 180 degrees * along the Y axis, plus whatever the parameters define. + * + * @return True if success to generate camera. False otherwise. */ - void ConfigureCamera(CameraActor& camera) const; + bool ConfigureCamera(CameraActor& camera, bool invertY = true) const; }; } // namespace Loader diff --git a/dali-scene3d/public-api/loader/dli-loader.cpp b/dali-scene3d/public-api/loader/dli-loader.cpp index 7eafcb7..536e29b 100644 --- a/dali-scene3d/public-api/loader/dli-loader.cpp +++ b/dali-scene3d/public-api/loader/dli-loader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -1730,7 +1730,7 @@ void DliLoader::Impl::GetCameraParameters(std::vector& cameras { auto& jsonCamera = (*i0).second; - ReadFloat(jsonCamera.GetChild("fov"), iCamera->yFov); + ReadFloat(jsonCamera.GetChild("fov"), iCamera->yFovDegree.degree); ReadFloat(jsonCamera.GetChild("near"), iCamera->zNear); ReadFloat(jsonCamera.GetChild("far"), iCamera->zFar); if(ReadVector(jsonCamera.GetChild("orthographic"), dummyFloatArray, 4u)) diff --git a/dali-scene3d/public-api/loader/gltf2-loader.cpp b/dali-scene3d/public-api/loader/gltf2-loader.cpp index 532bbb6..0744101 100644 --- a/dali-scene3d/public-api/loader/gltf2-loader.cpp +++ b/dali-scene3d/public-api/loader/gltf2-loader.cpp @@ -263,7 +263,7 @@ const auto CAMERA_PERSPECTIVE_READER = std::move(js::Reader() .Register(*js::MakeProperty("xmag", js::Read::Number, >::Camera::Orthographic::mXMag)) - .Register(*js::MakeProperty("ymag", js::Read::Number, >::Camera::Orthographic::mXMag)) + .Register(*js::MakeProperty("ymag", js::Read::Number, >::Camera::Orthographic::mYMag)) .Register(*js::MakeProperty("zfar", js::Read::Number, >::Camera::Orthographic::mZFar)) .Register(*js::MakeProperty("znear", js::Read::Number, >::Camera::Orthographic::mZNear))); @@ -578,7 +578,7 @@ void ConvertMaterial(const gt::Material& material, const std::unordered_map