Optimize some matrix multiply for projection matrix + Orthographic reflection
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / camera-actor-impl.cpp
index 0025ac8..f714d74 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.
 
 // INTERNAL INCLUDES
 #include <dali/devel-api/actors/camera-actor-devel.h>
+#include <dali/internal/common/matrix-utils.h>
 #include <dali/internal/event/common/projection.h>
 #include <dali/internal/event/common/property-helper.h>
 #include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/public-api/object/type-registry.h>
 
+#include <dali/internal/update/common/property-base.h>
 #include <dali/internal/update/manager/update-manager.h>
 
 namespace Dali
@@ -46,20 +48,22 @@ namespace
  */
 // clang-format off
 DALI_PROPERTY_TABLE_BEGIN
-DALI_PROPERTY( "type",                   INTEGER,  true,    false,   true,   Dali::CameraActor::Property::TYPE                  )
-DALI_PROPERTY( "projectionMode",         INTEGER,  true,    false,   true,   Dali::CameraActor::Property::PROJECTION_MODE       )
-DALI_PROPERTY( "fieldOfView",            FLOAT,    true,    false,   true,   Dali::CameraActor::Property::FIELD_OF_VIEW         )
-DALI_PROPERTY( "aspectRatio",            FLOAT,    true,    false,   true,   Dali::CameraActor::Property::ASPECT_RATIO          )
-DALI_PROPERTY( "nearPlaneDistance",      FLOAT,    true,    false,   true,   Dali::CameraActor::Property::NEAR_PLANE_DISTANCE   )
-DALI_PROPERTY( "farPlaneDistance",       FLOAT,    true,    false,   true,   Dali::CameraActor::Property::FAR_PLANE_DISTANCE    )
-DALI_PROPERTY( "leftPlaneDistance",      FLOAT,    true,    false,   true,   Dali::CameraActor::Property::LEFT_PLANE_DISTANCE   )
-DALI_PROPERTY( "rightPlaneDistance",     FLOAT,    true,    false,   true,   Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE  )
-DALI_PROPERTY( "topPlaneDistance",       FLOAT,    true,    false,   true,   Dali::CameraActor::Property::TOP_PLANE_DISTANCE    )
-DALI_PROPERTY( "bottomPlaneDistance",    FLOAT,    true,    false,   true,   Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE )
-DALI_PROPERTY( "targetPosition",         VECTOR3,  true,    false,   true,   Dali::CameraActor::Property::TARGET_POSITION       )
-DALI_PROPERTY( "projectionMatrix",       MATRIX,   false,   false,   true,   Dali::CameraActor::Property::PROJECTION_MATRIX     )
-DALI_PROPERTY( "viewMatrix",             MATRIX,   false,   false,   true,   Dali::CameraActor::Property::VIEW_MATRIX           )
-DALI_PROPERTY( "invertYAxis",            BOOLEAN,  true,    false,   true,   Dali::CameraActor::Property::INVERT_Y_AXIS         )
+DALI_PROPERTY( "type",                   INTEGER,  true,    false,   true,   Dali::CameraActor::Property::TYPE                      )
+DALI_PROPERTY( "projectionMode",         INTEGER,  true,    false,   true,   Dali::CameraActor::Property::PROJECTION_MODE           )
+DALI_PROPERTY( "fieldOfView",            FLOAT,    true,    true,    true,   Dali::CameraActor::Property::FIELD_OF_VIEW             )
+DALI_PROPERTY( "aspectRatio",            FLOAT,    true,    true,    true,   Dali::CameraActor::Property::ASPECT_RATIO              )
+DALI_PROPERTY( "nearPlaneDistance",      FLOAT,    true,    false,   true,   Dali::CameraActor::Property::NEAR_PLANE_DISTANCE       )
+DALI_PROPERTY( "farPlaneDistance",       FLOAT,    true,    false,   true,   Dali::CameraActor::Property::FAR_PLANE_DISTANCE        )
+DALI_PROPERTY( "leftPlaneDistance",      FLOAT,    false,   false,   true,   Dali::CameraActor::Property::LEFT_PLANE_DISTANCE       )
+DALI_PROPERTY( "rightPlaneDistance",     FLOAT,    false,   false,   true,   Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE      )
+DALI_PROPERTY( "topPlaneDistance",       FLOAT,    false,   false,   true,   Dali::CameraActor::Property::TOP_PLANE_DISTANCE        )
+DALI_PROPERTY( "bottomPlaneDistance",    FLOAT,    false,   false,   true,   Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE     )
+DALI_PROPERTY( "targetPosition",         VECTOR3,  true,    false,   true,   Dali::CameraActor::Property::TARGET_POSITION           )
+DALI_PROPERTY( "projectionMatrix",       MATRIX,   false,   false,   true,   Dali::CameraActor::Property::PROJECTION_MATRIX         )
+DALI_PROPERTY( "viewMatrix",             MATRIX,   false,   false,   true,   Dali::CameraActor::Property::VIEW_MATRIX               )
+DALI_PROPERTY( "invertYAxis",            BOOLEAN,  true,    false,   true,   Dali::CameraActor::Property::INVERT_Y_AXIS             )
+DALI_PROPERTY( "orthographicSize",       FLOAT,    true,    true,    true,   Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE    )
+DALI_PROPERTY( "projectionDirection",    INTEGER,  true,    false,   true,   Dali::DevelCameraActor::Property::PROJECTION_DIRECTION )
 DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX, CameraDefaultProperties )
 // clang-format on
 
@@ -103,7 +107,7 @@ void BuildOrthoPickingRay(const Matrix&   viewMatrix,
 
   // Transforms the touch point from the screen reference system to the world reference system.
   Matrix invViewProjection(false); // Don't initialize.
-  Matrix::Multiply(invViewProjection, viewMatrix, projectionMatrix);
+  MatrixUtils::MultiplyProjectionMatrix(invViewProjection, viewMatrix, projectionMatrix);
   if(!invViewProjection.Invert())
   {
     DALI_ASSERT_DEBUG(false);
@@ -134,11 +138,60 @@ void BuildOrthoPickingRay(const Matrix&   viewMatrix,
   rayDir.w = 1.0f;
 }
 
+/**
+ * @brief Helper class to calculate left/right/top/bottom plane distance by orthographicSize and something other info.
+ * It will resolve some confuse case of plane distance value.
+ * (Something like, Is top plane distance is positive or negative? is aspect ratio is width/height or height/width?)
+ */
+struct OrthographicSizeConverter
+{
+  constexpr OrthographicSizeConverter(float orthographicSize, float aspectRatio, Dali::DevelCameraActor::ProjectionDirection projectionDirection)
+  : mOrthographicSize(orthographicSize),
+    mAspectRatio(aspectRatio),
+    mProjectionDirection(projectionDirection)
+  {
+  }
+
+  inline float LeftPlaneDistance() const
+  {
+    return -(mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? mOrthographicSize * mAspectRatio : mOrthographicSize);
+  }
+
+  inline float RightPlaneDistance() const
+  {
+    return (mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? mOrthographicSize * mAspectRatio : mOrthographicSize);
+  }
+
+  inline float TopPlaneDistance() const
+  {
+    return (mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? mOrthographicSize : mOrthographicSize / mAspectRatio);
+  }
+
+  inline float BottomPlaneDistance() const
+  {
+    return -(mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? mOrthographicSize : mOrthographicSize / mAspectRatio);
+  }
+
+  float                                       mOrthographicSize;
+  float                                       mAspectRatio;
+  Dali::DevelCameraActor::ProjectionDirection mProjectionDirection;
+};
+
 } // namespace
 
 CameraActorPtr CameraActor::New(const Size& size)
 {
-  CameraActorPtr actor(new CameraActor(*CreateNode()));
+  // create camera. Cameras are owned by the update manager
+  SceneGraph::Camera*            camera = SceneGraph::Camera::New();
+  OwnerPointer<SceneGraph::Node> transferOwnership(camera);
+  Internal::ThreadLocalStorage*  tls = Internal::ThreadLocalStorage::GetInternal();
+
+  DALI_ASSERT_ALWAYS(tls && "ThreadLocalStorage is null");
+
+  // Send ownership of camera.
+  AddNodeMessage(tls->GetUpdateManager(), transferOwnership);
+
+  CameraActorPtr actor(new CameraActor(*camera));
 
   // Second-phase construction
   actor->Initialize();
@@ -155,19 +208,15 @@ CameraActorPtr CameraActor::New(const Size& size)
 
 CameraActor::CameraActor(const SceneGraph::Node& node)
 : Actor(Actor::BASIC, node),
-  mSceneObject(nullptr),
   mTarget(SceneGraph::Camera::DEFAULT_TARGET_POSITION),
   mType(SceneGraph::Camera::DEFAULT_TYPE),
   mProjectionMode(SceneGraph::Camera::DEFAULT_MODE),
   mProjectionDirection(SceneGraph::Camera::DEFAULT_PROJECTION_DIRECTION),
   mFieldOfView(SceneGraph::Camera::DEFAULT_FIELD_OF_VIEW),
+  mOrthographicSize(SceneGraph::Camera::DEFAULT_ORTHOGRAPHIC_SIZE),
   mAspectRatio(SceneGraph::Camera::DEFAULT_ASPECT_RATIO),
   mNearClippingPlane(SceneGraph::Camera::DEFAULT_NEAR_CLIPPING_PLANE),
   mFarClippingPlane(SceneGraph::Camera::DEFAULT_FAR_CLIPPING_PLANE),
-  mLeftClippingPlane(SceneGraph::Camera::DEFAULT_LEFT_CLIPPING_PLANE),
-  mRightClippingPlane(SceneGraph::Camera::DEFAULT_RIGHT_CLIPPING_PLANE),
-  mTopClippingPlane(SceneGraph::Camera::DEFAULT_TOP_CLIPPING_PLANE),
-  mBottomClippingPlane(SceneGraph::Camera::DEFAULT_BOTTOM_CLIPPING_PLANE),
   mInvertYAxis(SceneGraph::Camera::DEFAULT_INVERT_Y_AXIS),
   mPropertyChanged(false)
 {
@@ -175,26 +224,6 @@ CameraActor::CameraActor(const SceneGraph::Node& node)
 
 CameraActor::~CameraActor()
 {
-  if(EventThreadServices::IsCoreRunning())
-  {
-    // Create scene-object and transfer ownership through message
-    RemoveCameraMessage(GetEventThreadServices().GetUpdateManager(), mSceneObject);
-  }
-}
-
-void CameraActor::OnInitialize()
-{
-  // Create scene-object and keep raw pointer for message passing.
-  SceneGraph::Camera* sceneGraphCamera = SceneGraph::Camera::New();
-
-  // Store a pointer to this camera node inside the scene-graph camera.
-  sceneGraphCamera->SetNode(&GetNode());
-
-  mSceneObject = sceneGraphCamera;
-  OwnerPointer<SceneGraph::Camera> sceneGraphCameraOwner(sceneGraphCamera);
-
-  // Send message to inform update of this camera (and move ownership).
-  AddCameraMessage(GetEventThreadServices().GetUpdateManager(), sceneGraphCameraOwner);
 }
 
 void CameraActor::OnSceneConnectionInternal()
@@ -216,10 +245,7 @@ void CameraActor::OnSceneConnectionInternal()
 
 void CameraActor::SetReflectByPlane(const Vector4& plane)
 {
-  if(mSceneObject)
-  {
-    SetReflectByPlaneMessage(GetEventThreadServices(), *mSceneObject, plane);
-  }
+  SetReflectByPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), plane);
 }
 
 void CameraActor::SetTarget(const Vector3& target)
@@ -229,7 +255,7 @@ void CameraActor::SetTarget(const Vector3& target)
   {
     mTarget = target;
 
-    SetTargetPositionMessage(GetEventThreadServices(), *mSceneObject, mTarget);
+    SetTargetPositionMessage(GetEventThreadServices(), GetCameraSceneObject(), mTarget);
   }
 }
 
@@ -245,7 +271,7 @@ void CameraActor::SetType(Dali::Camera::Type type)
     mType = type;
 
     // sceneObject is being used in a separate thread; queue a message to set
-    SetTypeMessage(GetEventThreadServices(), *mSceneObject, mType);
+    SetTypeMessage(GetEventThreadServices(), GetCameraSceneObject(), mType);
   }
 }
 
@@ -261,7 +287,7 @@ void CameraActor::SetProjectionMode(Dali::Camera::ProjectionMode mode)
     mProjectionMode = mode;
 
     // sceneObject is being used in a separate thread; queue a message to set
-    SetProjectionModeMessage(GetEventThreadServices(), *mSceneObject, mProjectionMode);
+    SetProjectionModeMessage(GetEventThreadServices(), GetCameraSceneObject(), mProjectionMode);
   }
 }
 
@@ -278,7 +304,7 @@ void CameraActor::SetProjectionDirection(Dali::DevelCameraActor::ProjectionDirec
     mProjectionDirection = direction;
 
     // sceneObject is being used in a separate thread; queue a message to set
-    SetProjectionDirectionMessage(GetEventThreadServices(), *mSceneObject, mProjectionDirection);
+    SetProjectionDirectionMessage(GetEventThreadServices(), GetCameraSceneObject(), mProjectionDirection);
   }
 }
 
@@ -290,7 +316,7 @@ void CameraActor::SetFieldOfView(float fieldOfView)
     mFieldOfView = fieldOfView;
 
     // sceneObject is being used in a separate thread; queue a message to set
-    SetFieldOfViewMessage(GetEventThreadServices(), *mSceneObject, mFieldOfView);
+    BakeFieldOfViewMessage(GetEventThreadServices(), GetCameraSceneObject(), mFieldOfView);
   }
 }
 
@@ -299,6 +325,35 @@ float CameraActor::GetFieldOfView() const
   return mFieldOfView;
 }
 
+float CameraActor::GetCurrentFieldOfView() const
+{
+  // node is being used in a separate thread; copy the value from the previous update
+  return GetCameraSceneObject().GetFieldOfView(GetEventThreadServices().GetEventBufferIndex());
+}
+
+void CameraActor::SetOrthographicSize(float orthographicSize)
+{
+  mPropertyChanged = true;
+  if(!Equals(orthographicSize, mOrthographicSize))
+  {
+    mOrthographicSize = orthographicSize;
+
+    // sceneObject is being used in a separate thread; queue a message to set
+    BakeOrthographicSizeMessage(GetEventThreadServices(), GetCameraSceneObject(), mOrthographicSize);
+  }
+}
+
+float CameraActor::GetOrthographicSize() const
+{
+  return mOrthographicSize;
+}
+
+float CameraActor::GetCurrentOrthographicSize() const
+{
+  // node is being used in a separate thread; copy the value from the previous update
+  return GetCameraSceneObject().GetOrthographicSize(GetEventThreadServices().GetEventBufferIndex());
+}
+
 void CameraActor::SetAspectRatio(float aspectRatio)
 {
   mPropertyChanged = true;
@@ -307,7 +362,7 @@ void CameraActor::SetAspectRatio(float aspectRatio)
     mAspectRatio = aspectRatio;
 
     // sceneObject is being used in a separate thread; queue a message to set
-    SetAspectRatioMessage(GetEventThreadServices(), *mSceneObject, mAspectRatio);
+    BakeAspectRatioMessage(GetEventThreadServices(), GetCameraSceneObject(), mAspectRatio);
   }
 }
 
@@ -316,6 +371,12 @@ float CameraActor::GetAspectRatio() const
   return mAspectRatio;
 }
 
+float CameraActor::GetCurrentAspectRatio() const
+{
+  // node is being used in a separate thread; copy the value from the previous update
+  return GetCameraSceneObject().GetAspectRatio(GetEventThreadServices().GetEventBufferIndex());
+}
+
 void CameraActor::SetNearClippingPlane(float nearClippingPlane)
 {
   mPropertyChanged = true;
@@ -324,7 +385,7 @@ void CameraActor::SetNearClippingPlane(float nearClippingPlane)
     mNearClippingPlane = nearClippingPlane;
 
     // sceneObject is being used in a separate thread; queue a message to set
-    SetNearClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mNearClippingPlane);
+    SetNearClippingPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), mNearClippingPlane);
   }
 }
 
@@ -341,7 +402,7 @@ void CameraActor::SetFarClippingPlane(float farClippingPlane)
     mFarClippingPlane = farClippingPlane;
 
     // sceneObject is being used in a separate thread; queue a message to set
-    SetFarClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mFarClippingPlane);
+    SetFarClippingPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), mFarClippingPlane);
   }
 }
 
@@ -350,54 +411,6 @@ float CameraActor::GetFarClippingPlane() const
   return mFarClippingPlane;
 }
 
-void CameraActor::SetLeftClippingPlane(float leftClippingPlane)
-{
-  mPropertyChanged = true;
-  if(!Equals(leftClippingPlane, mLeftClippingPlane))
-  {
-    mLeftClippingPlane = leftClippingPlane;
-
-    // sceneObject is being used in a separate thread; queue a message to set
-    SetLeftClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mLeftClippingPlane);
-  }
-}
-
-void CameraActor::SetRightClippingPlane(float rightClippingPlane)
-{
-  mPropertyChanged = true;
-  if(!Equals(rightClippingPlane, mRightClippingPlane))
-  {
-    mRightClippingPlane = rightClippingPlane;
-
-    // sceneObject is being used in a separate thread; queue a message to set
-    SetRightClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mRightClippingPlane);
-  }
-}
-
-void CameraActor::SetTopClippingPlane(float topClippingPlane)
-{
-  mPropertyChanged = true;
-  if(!Equals(topClippingPlane, mTopClippingPlane))
-  {
-    mTopClippingPlane = topClippingPlane;
-
-    // sceneObject is being used in a separate thread; queue a message to set
-    SetTopClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mTopClippingPlane);
-  }
-}
-
-void CameraActor::SetBottomClippingPlane(float bottomClippingPlane)
-{
-  mPropertyChanged = true;
-  if(!Equals(bottomClippingPlane, mBottomClippingPlane))
-  {
-    mBottomClippingPlane = bottomClippingPlane;
-
-    // sceneObject is being used in a separate thread; queue a message to set
-    SetBottomClippingPlaneMessage(GetEventThreadServices(), *mSceneObject, mBottomClippingPlane);
-  }
-}
-
 void CameraActor::SetInvertYAxis(bool invertYAxis)
 {
   if(invertYAxis != mInvertYAxis)
@@ -405,7 +418,7 @@ void CameraActor::SetInvertYAxis(bool invertYAxis)
     mInvertYAxis = invertYAxis;
 
     // sceneObject is being used in a separate thread; queue a message to set
-    SetInvertYAxisMessage(GetEventThreadServices(), *mSceneObject, mInvertYAxis);
+    SetInvertYAxisMessage(GetEventThreadServices(), GetCameraSceneObject(), mInvertYAxis);
   }
 }
 
@@ -417,7 +430,7 @@ bool CameraActor::GetInvertYAxis() const
 void CameraActor::SetPerspectiveProjection(const Size& size)
 {
   SetProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION);
-  mCanvasSize = size;
+  mCanvasSize = static_cast<const Vector2>(size);
 
   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
   {
@@ -434,43 +447,13 @@ void CameraActor::SetPerspectiveProjection(const Size& size)
       return;
     }
   }
-
-  float width  = mCanvasSize.width;
-  float height = mCanvasSize.height;
-
-  float nearClippingPlane;
-  float farClippingPlane;
-  float cameraZ;
-  CalculateClippingAndZ(width, height, nearClippingPlane, farClippingPlane, cameraZ);
-
-  // calculate the position of the camera to have the desired aspect ratio
-  const float fieldOfView = 2.0f * std::atan((mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? height : width) * 0.5f / cameraZ);
-
-  // unless it is too small, we want at least as much space to the back as we have torwards the front
-  const float minClippingFarPlane = 2.f * nearClippingPlane;
-  if(farClippingPlane < minClippingFarPlane)
-  {
-    farClippingPlane = minClippingFarPlane;
-  }
-
-  const float aspectRatio = width / height;
-
-  // sceneObject is being used in a separate thread; queue a message to set
-  SetFieldOfView(fieldOfView);
-  SetNearClippingPlane(nearClippingPlane);
-  SetFarClippingPlane(farClippingPlane);
-  SetLeftClippingPlane(width * -0.5f);
-  SetRightClippingPlane(width * 0.5f);
-  SetTopClippingPlane(height * 0.5f);     // Top is +ve to keep consistency with orthographic values
-  SetBottomClippingPlane(height * -0.5f); // Bottom is -ve to keep consistency with orthographic values
-  SetAspectRatio(aspectRatio);
-  SetZ(cameraZ);
+  ApplyDefaultProjection();
 }
 
-void CameraActor::SetOrthographicProjection(const Vector2& size)
+void CameraActor::SetOrthographicProjection(const Size& size)
 {
   SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
-  mCanvasSize = size;
+  mCanvasSize = static_cast<const Vector2>(size);
 
   if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
   {
@@ -488,24 +471,42 @@ void CameraActor::SetOrthographicProjection(const Vector2& size)
     }
   }
 
+  ApplyDefaultProjection();
+}
+
+void CameraActor::ApplyDefaultProjection()
+{
+  const float width  = mCanvasSize.width;
+  const float height = mCanvasSize.height;
+
   // Choose near, far and Z parameters to match the SetPerspectiveProjection above.
   float nearClippingPlane;
   float farClippingPlane;
   float cameraZ;
-  CalculateClippingAndZ(size.width, size.height, nearClippingPlane, farClippingPlane, cameraZ);
-  SetOrthographicProjection(-size.x * 0.5f, size.x * 0.5f, size.y * 0.5f, size.y * -0.5f, nearClippingPlane, farClippingPlane);
-  SetZ(cameraZ);
-}
+  CalculateClippingAndZ(width, height, nearClippingPlane, farClippingPlane, cameraZ);
 
-void CameraActor::SetOrthographicProjection(float left, float right, float top, float bottom, float near, float far)
-{
-  SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
-  SetLeftClippingPlane(left);
-  SetRightClippingPlane(right);
-  SetTopClippingPlane(top);
-  SetBottomClippingPlane(bottom);
-  SetNearClippingPlane(near);
-  SetFarClippingPlane(far);
+  // calculate orthographic size.
+  const float orthographicSize = (mProjectionDirection == DevelCameraActor::ProjectionDirection::VERTICAL ? height : width) * 0.5f;
+
+  // calculate the position of the camera to have the desired aspect ratio
+  const float fieldOfView = 2.0f * std::atan(orthographicSize / cameraZ);
+
+  // unless it is too small, we want at least as much space to the back as we have torwards the front
+  const float minClippingFarPlane = 2.f * nearClippingPlane;
+  if(farClippingPlane < minClippingFarPlane)
+  {
+    farClippingPlane = minClippingFarPlane;
+  }
+
+  const float aspectRatio = width / height;
+
+  // sceneObject is being used in a separate thread; queue a message to set
+  SetFieldOfView(fieldOfView);
+  SetNearClippingPlane(nearClippingPlane);
+  SetFarClippingPlane(farClippingPlane);
+  SetAspectRatio(aspectRatio);
+  SetOrthographicSize(orthographicSize);
+  SetZ(cameraZ);
 }
 
 bool CameraActor::BuildPickingRay(const Vector2&  screenCoordinates,
@@ -526,7 +527,7 @@ bool CameraActor::BuildPickingRay(const Vector2&  screenCoordinates,
                  static_cast<float>(viewport.height) - (screenCoordinates.y - static_cast<float>(viewport.y)),
                  0.f,
                  1.f);
-    const Matrix& inverseViewProjection = mSceneObject->GetInverseViewProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
+    const Matrix& inverseViewProjection = GetCameraSceneObject().GetInverseViewProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
     success                             = Unproject(near, inverseViewProjection, static_cast<float>(viewport.width), static_cast<float>(viewport.height), near);
 
     // Compute the ray's director vector.
@@ -556,7 +557,7 @@ const Matrix& CameraActor::GetViewMatrix() const
 {
   if(OnScene())
   {
-    return mSceneObject->GetViewMatrix(GetEventThreadServices().GetEventBufferIndex());
+    return GetCameraSceneObject().GetViewMatrix(GetEventThreadServices().GetEventBufferIndex());
   }
   else
   {
@@ -568,22 +569,22 @@ const Matrix& CameraActor::GetProjectionMatrix() const
 {
   if(OnScene())
   {
-    return mSceneObject->GetProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
+    return GetCameraSceneObject().GetProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
   }
   else
   {
     return Matrix::IDENTITY;
   }
 }
-const SceneGraph::Camera* CameraActor::GetCamera() const
+const SceneGraph::Camera& CameraActor::GetCameraSceneObject() const
 {
-  return mSceneObject;
+  return static_cast<const SceneGraph::Camera&>(GetNode());
 }
 
 void CameraActor::RotateProjection(int rotationAngle)
 {
   // sceneObject is being used in a separate thread; queue a message to set
-  RotateProjectionMessage(GetEventThreadServices(), *mSceneObject, rotationAngle);
+  RotateProjectionMessage(GetEventThreadServices(), GetCameraSceneObject(), rotationAngle);
 }
 
 void CameraActor::SetDefaultProperty(Property::Index index, const Property::Value& propertyValue)
@@ -613,6 +614,11 @@ void CameraActor::SetDefaultProperty(Property::Index index, const Property::Valu
         SetFieldOfView(propertyValue.Get<float>()); // set to 0 in case property is not float
         break;
       }
+      case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
+      {
+        SetOrthographicSize(propertyValue.Get<float>()); // set to 0 in case property is not float
+        break;
+      }
       case Dali::CameraActor::Property::ASPECT_RATIO:
       {
         SetAspectRatio(propertyValue.Get<float>()); // set to 0 in case property is not float
@@ -630,22 +636,22 @@ void CameraActor::SetDefaultProperty(Property::Index index, const Property::Valu
       }
       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
       {
-        SetLeftClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
+        DALI_LOG_WARNING("LEFT_PLANE_DISTANCE is read-only\n");
         break;
       }
       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
       {
-        SetRightClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
+        DALI_LOG_WARNING("RIGHT_PLANE_DISTANCE is read-only\n");
         break;
       }
       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
       {
-        SetTopClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
+        DALI_LOG_WARNING("TOP_PLANE_DISTANCE is read-only\n");
         break;
       }
       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
       {
-        SetBottomClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
+        DALI_LOG_WARNING("BOTTOM_PLANE_DISTANCE is read-only\n");
         break;
       }
       case Dali::CameraActor::Property::TARGET_POSITION:
@@ -716,6 +722,11 @@ Property::Value CameraActor::GetDefaultProperty(Property::Index index) const
         ret = mFieldOfView;
         break;
       }
+      case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
+      {
+        ret = mOrthographicSize;
+        break;
+      }
       case Dali::CameraActor::Property::ASPECT_RATIO:
       {
         ret = mAspectRatio;
@@ -733,22 +744,22 @@ Property::Value CameraActor::GetDefaultProperty(Property::Index index) const
       }
       case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
       {
-        ret = mLeftClippingPlane;
+        ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).LeftPlaneDistance();
         break;
       }
       case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
       {
-        ret = mRightClippingPlane;
+        ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).RightPlaneDistance();
         break;
       }
       case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
       {
-        ret = mTopClippingPlane;
+        ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).TopPlaneDistance();
         break;
       }
       case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
       {
-        ret = mBottomClippingPlane;
+        ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).BottomPlaneDistance();
         break;
       }
       case Dali::CameraActor::Property::TARGET_POSITION:
@@ -791,26 +802,172 @@ Property::Value CameraActor::GetDefaultPropertyCurrentValue(Property::Index inde
   }
   else
   {
-    ret = GetDefaultProperty(index); // Most are event-side properties, the scene-graph properties are only on the scene-graph
+    switch(index)
+    {
+      case Dali::CameraActor::Property::FIELD_OF_VIEW:
+      {
+        ret = GetCurrentFieldOfView();
+        break;
+      }
+      case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
+      {
+        ret = GetCurrentOrthographicSize();
+        break;
+      }
+      case Dali::CameraActor::Property::ASPECT_RATIO:
+      {
+        ret = GetCurrentAspectRatio();
+        break;
+      }
+      case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
+      {
+        ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).LeftPlaneDistance();
+        break;
+      }
+      case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
+      {
+        ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).RightPlaneDistance();
+        break;
+      }
+      case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
+      {
+        ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).TopPlaneDistance();
+        break;
+      }
+      case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
+      {
+        ret = OrthographicSizeConverter(GetCurrentOrthographicSize(), GetCurrentAspectRatio(), mProjectionDirection).BottomPlaneDistance();
+        break;
+      }
+      default:
+      {
+        ret = GetDefaultProperty(index); // Most are event-side properties, the scene-graph properties are only on the scene-graph
+      }
+    } // switch(index)
   }
 
   return ret;
 }
 
+void CameraActor::OnNotifyDefaultPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType)
+{
+  if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
+  {
+    Actor::OnNotifyDefaultPropertyAnimation(animation, index, value, animationType);
+  }
+  else
+  {
+    switch(animationType)
+    {
+      case Animation::TO:
+      case Animation::BETWEEN:
+      {
+        switch(index)
+        {
+          case Dali::CameraActor::Property::FIELD_OF_VIEW:
+          {
+            value.Get(mFieldOfView);
+            break;
+          }
+          case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
+          {
+            value.Get(mOrthographicSize);
+            break;
+          }
+          case Dali::CameraActor::Property::ASPECT_RATIO:
+          {
+            value.Get(mAspectRatio);
+            break;
+          }
+        }
+        break;
+      }
+      case Animation::BY:
+      {
+        switch(index)
+        {
+          case Dali::CameraActor::Property::FIELD_OF_VIEW:
+          {
+            AdjustValue<float>(mFieldOfView, value);
+            break;
+          }
+          case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
+          {
+            AdjustValue<float>(mOrthographicSize, value);
+            break;
+          }
+          case Dali::CameraActor::Property::ASPECT_RATIO:
+          {
+            AdjustValue<float>(mAspectRatio, value);
+            break;
+          }
+        }
+        break;
+      }
+    }
+  }
+}
+
+const SceneGraph::PropertyBase* CameraActor::GetSceneObjectAnimatableProperty(Property::Index index) const
+{
+  const SceneGraph::PropertyBase* property(nullptr);
+  switch(index)
+  {
+    case Dali::CameraActor::Property::FIELD_OF_VIEW:
+    {
+      property = GetCameraSceneObject().GetFieldOfView();
+      break;
+    }
+    case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
+    {
+      property = GetCameraSceneObject().GetOrthographicSize();
+      break;
+    }
+    case Dali::CameraActor::Property::ASPECT_RATIO:
+    {
+      property = GetCameraSceneObject().GetAspectRatio();
+      break;
+    }
+      // no default on purpose as we chain method up to actor
+  }
+  if(!property)
+  {
+    // not our property, ask base
+    property = Actor::GetSceneObjectAnimatableProperty(index);
+  }
+
+  return property;
+}
+
 const PropertyInputImpl* CameraActor::GetSceneObjectInputProperty(Property::Index index) const
 {
   const PropertyInputImpl* property(nullptr);
 
   switch(index)
   {
+    case Dali::CameraActor::Property::FIELD_OF_VIEW:
+    {
+      property = GetCameraSceneObject().GetFieldOfView();
+      break;
+    }
+    case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
+    {
+      property = GetCameraSceneObject().GetOrthographicSize();
+      break;
+    }
+    case Dali::CameraActor::Property::ASPECT_RATIO:
+    {
+      property = GetCameraSceneObject().GetAspectRatio();
+      break;
+    }
     case Dali::CameraActor::Property::PROJECTION_MATRIX:
     {
-      property = mSceneObject->GetProjectionMatrix();
+      property = GetCameraSceneObject().GetProjectionMatrix();
       break;
     }
     case Dali::CameraActor::Property::VIEW_MATRIX:
     {
-      property = mSceneObject->GetViewMatrix();
+      property = GetCameraSceneObject().GetViewMatrix();
       break;
     }
       // no default on purpose as we chain method up to actor