Generate Camera from loaded model 30/288530/9
authorEunki Hong <eunkiki.hong@samsung.com>
Fri, 17 Feb 2023 14:15:35 +0000 (23:15 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Fri, 24 Feb 2023 04:51:32 +0000 (13:51 +0900)
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: Ief1571d1e8b522c1785b8721c279713b20760a99
Signed-off-by: Eunki Hong <eunkiki.hong@samsung.com>
13 files changed:
automated-tests/resources/AnimatedCube.gltf
automated-tests/src/dali-scene3d/utc-Dali-CameraParameters.cpp
automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp
automated-tests/src/dali-scene3d/utc-Dali-Model.cpp
dali-scene3d/internal/controls/model/model-impl.cpp
dali-scene3d/internal/controls/model/model-impl.h
dali-scene3d/internal/loader/gltf2-asset.h
dali-scene3d/public-api/controls/model/model.cpp
dali-scene3d/public-api/controls/model/model.h
dali-scene3d/public-api/loader/camera-parameters.cpp
dali-scene3d/public-api/loader/camera-parameters.h
dali-scene3d/public-api/loader/dli-loader.cpp
dali-scene3d/public-api/loader/gltf2-loader.cpp

index 7787c046a7f3ac63920c01472b812456190c817a..807c07e686ef4bd923d6ef1e6840995709f80544 100644 (file)
         "camera" : 1,
         "translation" : [ 0.5, 0.5, 3.0 ],
         "children": [
-          4
+          4, 5, 6, 7
         ]
       },
       {
             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,
         "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": [
index 5fec8f2267a64415ba05064e1bb996d522616e5f..83f345c22ee8b22f5fcf9cc6ebf95d2b5c7bb4ac 100644 (file)
@@ -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<float>(), Radian(Degree(camParams.yFov)).radian);
+      DALI_TEST_EQUAL(camera.GetProperty(Dali::CameraActor::Property::FIELD_OF_VIEW).Get<float>(), Radian(camParams.yFovDegree).radian);
     }
     else
     {
index a485f0fd486851fc6f34b9483ad28c4a52b710db..bcb61b53826c1a5486caf91f0fa28ee7e775818e 100644 (file)
@@ -179,7 +179,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());
@@ -452,7 +452,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());
index 5d2c344e2179398922ee309f2ae8006c00a72fdb..18bd46c5d28db3fc0a521eb37ba8e5e67ec8cfd6 100644 (file)
@@ -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 <dali-scene3d/public-api/controls/model/model.h>
 
+#include <dali/devel-api/actors/camera-actor-devel.h>
+
 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<int>(Dali::CameraActor::Property::PROJECTION_MODE), rhs.GetProperty<int>(Dali::CameraActor::Property::PROJECTION_MODE), TEST_LOCATION);
+    DALI_TEST_EQUALS(lhs.GetProperty<float>(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE), rhs.GetProperty<float>(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE), TEST_LOCATION);
+
+    if(lhs.GetProperty<int>(Dali::CameraActor::Property::PROJECTION_MODE) == static_cast<int>(Dali::Camera::ProjectionMode::PERSPECTIVE_PROJECTION))
+    {
+      DALI_TEST_EQUALS(lhs.GetProperty<float>(Dali::CameraActor::Property::FIELD_OF_VIEW), rhs.GetProperty<float>(Dali::CameraActor::Property::FIELD_OF_VIEW), TEST_LOCATION);
+      // TODO : Open this test when infinity far projection implement.
+      //DALI_TEST_EQUALS(lhs.GetProperty<float>(Dali::CameraActor::Property::FAR_PLANE_DISTANCE), rhs.GetProperty<float>(Dali::CameraActor::Property::FAR_PLANE_DISTANCE), TEST_LOCATION);
+    }
+    else
+    {
+      DALI_TEST_EQUALS(lhs.GetProperty<float>(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE), rhs.GetProperty<float>(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE), TEST_LOCATION);
+      DALI_TEST_EQUALS(lhs.GetProperty<float>(Dali::CameraActor::Property::FAR_PLANE_DISTANCE), rhs.GetProperty<float>(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);
index 31e75e555bd286dd9b2c3d097f4b4da6bb150ba8..e5d5e78c1c90789fa1bc3df2a8cea9bb8cbe86d0 100644 (file)
@@ -116,8 +116,7 @@ void ConfigureBlendShapeShaders(
   Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
 {
   std::vector<std::string> errors;
-  auto                     onError = [&errors](const std::string& msg)
-  { errors.push_back(msg); };
+  auto                     onError = [&errors](const std::string& msg) { errors.push_back(msg); };
   if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
   {
     Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
@@ -384,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
@@ -583,6 +621,45 @@ void Model::UpdateImageBasedLightScaleFactor()
   }
 }
 
+void Model::ApplyCameraTransform(Dali::CameraActor camera) const
+{
+  Vector3    selfPosition    = Self().GetProperty<Vector3>(Actor::Property::POSITION);
+  Quaternion selfOrientation = Self().GetProperty<Quaternion>(Actor::Property::ORIENTATION);
+  Vector3    selfScale       = Self().GetProperty<Vector3>(Actor::Property::SCALE);
+
+  Vector3    cameraPosition    = camera.GetProperty<Vector3>(Actor::Property::POSITION);
+  Quaternion cameraOrientation = camera.GetProperty<Quaternion>(Actor::Property::ORIENTATION);
+  Vector3    cameraScale       = camera.GetProperty<Vector3>(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)
@@ -622,6 +699,8 @@ void Model::OnModelLoadComplete()
   auto* resources = &(mModelLoadTask->mResources);
   auto* scene     = &(mModelLoadTask->mScene);
   CreateAnimations(*scene);
+  ResetCameraParameters();
+
   if(!resources->mEnvironmentMaps.empty())
   {
     mDefaultDiffuseTexture  = resources->mEnvironmentMaps.front().second.mDiffuse;
@@ -745,10 +824,10 @@ void Model::CreateModel()
 
 void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
 {
+  mAnimations.clear();
   if(!mModelLoadTask->mAnimations.empty())
   {
-    auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property)
-    {
+    auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
       if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
       {
         return mModelRoot.FindChildByName(property.mNodeName);
@@ -761,7 +840,6 @@ void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
       return mModelRoot.FindChildById(node->mNodeId);
     };
 
-    mAnimations.clear();
     for(auto&& animation : mModelLoadTask->mAnimations)
     {
       Dali::Animation anim = animation.ReAnimate(getActor);
@@ -770,6 +848,16 @@ void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
   }
 }
 
+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
index 36e3a9af214d4cd9a6d323227e693d98e200c3e0..fea5d60d89ba1230884e34b986f967ed1914bd54 100644 (file)
@@ -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 <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali/public-api/actors/camera-actor.h>
 #include <dali/public-api/actors/layer.h>
 #include <dali/public-api/animation/animation.h>
 #include <dali/public-api/object/weak-handle.h>
@@ -47,6 +48,7 @@ class Model : public Dali::Toolkit::Internal::Control, public ImageBasedLightObs
 {
 public:
   using AnimationData = std::pair<std::string, Dali::Animation>;
+  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()
@@ -254,11 +281,17 @@ private:
    */
   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<AnimationData>     mAnimations;
+  std::vector<CameraData>        mCameraParameters;
   std::vector<WeakHandle<Actor>> mRenderableActors;
   WeakHandle<Scene3D::SceneView> mParentSceneView;
 
index 2a1392a145d7789b9232eee087384f56af790641..657680330a5eb52a3568f9c89a28105674b85fb4 100644 (file)
@@ -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.
  */
 
 // INTERNAL INCLUDES
-#include "dali-scene3d/internal/loader/json-reader.h"
-#include "dali-scene3d/public-api/loader/index.h"
+#include <dali-scene3d/internal/loader/json-reader.h>
+#include <dali-scene3d/public-api/loader/index.h>
 
 // EXTERNAL INCLUDES
+#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>
 #include <cstdint>
 #include <memory>
-#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<typename T>
 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
   };
index c0369ab4469191c7663d738e56dd115cb7925d79..fa792f9a448b4b68702f7783c27501338e9aaa88 100644 (file)
@@ -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
index 45ceca181b808609c91cb4de496a03b1fd861b8e..ce723eaa7ee123dbf2674aaa3bff1c12f2a3a64d 100644 (file)
@@ -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 <dali-toolkit/public-api/controls/control.h>
+#include <dali/public-api/actors/camera-actor.h>
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/rendering/texture.h>
 
@@ -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
   /**
index 270f84b94b418bce7a719826645508858328d836..cc9a351a20f06bb206277f1c9d760fb386b1f130 100644 (file)
@@ -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.
  * 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 <dali-scene3d/public-api/loader/camera-parameters.h>
+
+// EXTERNAL INCLUDES
+#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>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/loader/gltf2-asset.h> // for gltf2::UNDEFINED_FLOAT_VALUE
+#include <dali-scene3d/public-api/loader/utils.h>
 
 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
index 70060e5b3fe9feee7d609565d624a9b9e5c27c86..9fde07161c7b24d6ed56020391d870c65390ba92 100644 (file)
@@ -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.
  */
 
 // INTERNAL INCLUDES
-#include "dali-scene3d/public-api/api.h"
-#include "dali-scene3d/public-api/loader/view-projection.h"
+#include <dali-scene3d/public-api/api.h>
+#include <dali-scene3d/public-api/loader/view-projection.h>
 
 // EXTERNAL INCLUDES
-#include "dali/public-api/math/matrix.h"
-#include "dali/public-api/math/vector3.h"
+#include <dali/public-api/math/degree.h>
+#include <dali/public-api/math/matrix.h>
+#include <dali/public-api/math/vector3.h>
 
 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
index 8953f1a130c2f876cdac4343bbc9d821d56b462e..1a087c9131dac6204ded47b28ee45476c35541da 100644 (file)
@@ -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.
@@ -57,12 +57,12 @@ namespace rs = RendererState;
 
 namespace
 {
-const char* NODES         = "nodes";
-const char* SCENES        = "scenes";
-const char* NODE          = "node";
-const char* URI           = "uri";
-const char* URL           = "url";
-const char* HINTS         = "hints";
+const char* NODES  = "nodes";
+const char* SCENES = "scenes";
+const char* NODE   = "node";
+const char* URI    = "uri";
+const char* URL    = "url";
+const char* HINTS  = "hints";
 const char* NAME("name");
 const char* BLEND_SHAPE_HEADER("blendShapeHeader");
 const char* BLEND_SHAPES("blendShapes");
@@ -1729,7 +1729,7 @@ void DliLoader::Impl::GetCameraParameters(std::vector<CameraParameters>& 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))
index 9068b7fe3073fc0e95054583d3451facd33c7c58..05bd72cc9dc38ce63d91819ea1767e8aa2342fdb 100644 (file)
@@ -47,13 +47,13 @@ namespace
 Dali::Mutex gInitializeMutex;
 Dali::Mutex gReadMutex;
 
-const char* POSITION_PROPERTY("position");
-const char* ORIENTATION_PROPERTY("orientation");
-const char* SCALE_PROPERTY("scale");
-const char* BLEND_SHAPE_WEIGHTS_UNIFORM("uBlendShapeWeight");
-const char* MRENDERER_MODEL_IDENTIFICATION("M-Renderer");
-const char* ROOT_NODE_NAME("RootNode");
-const Vector3     SCALE_TO_ADJUST(100.0f, 100.0f, 100.0f);
+const char*   POSITION_PROPERTY("position");
+const char*   ORIENTATION_PROPERTY("orientation");
+const char*   SCALE_PROPERTY("scale");
+const char*   BLEND_SHAPE_WEIGHTS_UNIFORM("uBlendShapeWeight");
+const char*   MRENDERER_MODEL_IDENTIFICATION("M-Renderer");
+const char*   ROOT_NODE_NAME("RootNode");
+const Vector3 SCALE_TO_ADJUST(100.0f, 100.0f, 100.0f);
 
 const Geometry::Type GLTF2_TO_DALI_PRIMITIVES[]{
   Geometry::POINTS,
@@ -263,7 +263,7 @@ const auto CAMERA_PERSPECTIVE_READER = std::move(js::Reader<gt::Camera::Perspect
 
 const auto CAMERA_ORTHOGRAPHIC_READER = std::move(js::Reader<gt::Camera::Orthographic>()
                                                     .Register(*js::MakeProperty("xmag", js::Read::Number<float>, &gt::Camera::Orthographic::mXMag))
-                                                    .Register(*js::MakeProperty("ymag", js::Read::Number<float>, &gt::Camera::Orthographic::mXMag))
+                                                    .Register(*js::MakeProperty("ymag", js::Read::Number<float>, &gt::Camera::Orthographic::mYMag))
                                                     .Register(*js::MakeProperty("zfar", js::Read::Number<float>, &gt::Camera::Orthographic::mZFar))
                                                     .Register(*js::MakeProperty("znear", js::Read::Number<float>, &gt::Camera::Orthographic::mZNear)));
 
@@ -578,7 +578,7 @@ void ConvertMaterial(const gt::Material& material, const std::unordered_map<std:
     matDef.mEmissiveFactor = material.mEmissiveFactor;
   }
 
-  if(material.mMaterialExtensions.mMaterialIor.mIor < MAXFLOAT)
+  if(!Dali::Equals(material.mMaterialExtensions.mMaterialIor.mIor, gltf2::UNDEFINED_FLOAT_VALUE))
   {
     float ior                  = material.mMaterialExtensions.mMaterialIor.mIor;
     matDef.mDielectricSpecular = powf((ior - 1.0f) / (ior + 1.0f), 2.0f);
@@ -812,18 +812,33 @@ void ConvertCamera(const gt::Camera& camera, CameraParameters& camParams)
   if(camParams.isPerspective)
   {
     auto& perspective = camera.mPerspective;
-    camParams.yFov    = Degree(Radian(perspective.mYFov)).degree;
-    camParams.zNear   = perspective.mZNear;
-    camParams.zFar    = perspective.mZFar;
+    if(!Dali::Equals(perspective.mYFov, gltf2::UNDEFINED_FLOAT_VALUE))
+    {
+      camParams.yFovDegree = Degree(Radian(perspective.mYFov));
+    }
+    else
+    {
+      camParams.yFovDegree = Degree(gltf2::UNDEFINED_FLOAT_VALUE);
+    }
+    camParams.zNear = perspective.mZNear;
+    camParams.zFar  = perspective.mZFar;
     // TODO: yes, we seem to ignore aspectRatio in CameraParameters.
   }
   else
   {
-    auto& ortho                = camera.mOrthographic;
-    camParams.orthographicSize = ortho.mYMag * .5f;
-    camParams.aspectRatio      = ortho.mXMag / ortho.mYMag;
-    camParams.zNear            = ortho.mZNear;
-    camParams.zFar             = ortho.mZFar;
+    auto& ortho = camera.mOrthographic;
+    if(!Dali::Equals(ortho.mYMag, gltf2::UNDEFINED_FLOAT_VALUE) && !Dali::Equals(ortho.mXMag, gltf2::UNDEFINED_FLOAT_VALUE))
+    {
+      camParams.orthographicSize = ortho.mYMag * .5f;
+      camParams.aspectRatio      = ortho.mXMag / ortho.mYMag;
+    }
+    else
+    {
+      camParams.orthographicSize = gltf2::UNDEFINED_FLOAT_VALUE;
+      camParams.aspectRatio      = gltf2::UNDEFINED_FLOAT_VALUE;
+    }
+    camParams.zNear = ortho.mZNear;
+    camParams.zFar  = ortho.mZFar;
   }
 }