Optimize some matrix multiply for projection matrix + Orthographic reflection
[platform/core/uifw/dali-core.git] / dali / internal / event / actors / camera-actor-impl.cpp
index 7ee2ef1..f714d74 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 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.
 #include <cstring> // for strcmp
 
 // INTERNAL INCLUDES
-#include <dali/public-api/common/stage.h>
-#include <dali/public-api/object/type-registry.h>
-#include <dali/internal/event/actor-attachments/camera-attachment-impl.h>
-#include <dali/internal/event/common/property-helper.h>
-#include <dali/internal/event/common/stage-impl.h>
-#include <dali/internal/event/render-tasks/render-task-impl.h>
-#include <dali/internal/event/render-tasks/render-task-list-impl.h>
+#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/integration-api/debug.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
 {
-
 namespace Internal
 {
-
 namespace
 {
-
 // Properties
 
 /**
@@ -49,29 +46,33 @@ namespace
  * particularly for the default properties.
  *              Name                     Type   writable animatable constraint-input  enum for index-checking
  */
+// clang-format off
 DALI_PROPERTY_TABLE_BEGIN
-DALI_PROPERTY( "type",                   STRING,   true,    false,   true,   Dali::CameraActor::Property::TYPE                  )
-DALI_PROPERTY( "projection-mode",        STRING,   true,    false,   true,   Dali::CameraActor::Property::PROJECTION_MODE       )
-DALI_PROPERTY( "field-of-view",          FLOAT,    true,    false,   true,   Dali::CameraActor::Property::FIELD_OF_VIEW         )
-DALI_PROPERTY( "aspect-ratio",           FLOAT,    true,    false,   true,   Dali::CameraActor::Property::ASPECT_RATIO          )
-DALI_PROPERTY( "near-plane-distance",    FLOAT,    true,    false,   true,   Dali::CameraActor::Property::NEAR_PLANE_DISTANCE   )
-DALI_PROPERTY( "far-plane-distance",     FLOAT,    true,    false,   true,   Dali::CameraActor::Property::FAR_PLANE_DISTANCE    )
-DALI_PROPERTY( "left-plane-distance",    FLOAT,    true,    false,   true,   Dali::CameraActor::Property::LEFT_PLANE_DISTANCE   )
-DALI_PROPERTY( "right-plane-distance",   FLOAT,    true,    false,   true,   Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE  )
-DALI_PROPERTY( "top-plane-distance",     FLOAT,    true,    false,   true,   Dali::CameraActor::Property::TOP_PLANE_DISTANCE    )
-DALI_PROPERTY( "bottom-plane-distance",  FLOAT,    true,    false,   true,   Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE )
-DALI_PROPERTY( "target-position",        VECTOR3,  true,    false,   true,   Dali::CameraActor::Property::TARGET_POSITION       )
-DALI_PROPERTY( "projection-matrix",      MATRIX,   false,   false,   true,   Dali::CameraActor::Property::PROJECTION_MATRIX     )
-DALI_PROPERTY( "view-matrix",            MATRIX,   false,   false,   true,   Dali::CameraActor::Property::VIEW_MATRIX           )
-DALI_PROPERTY( "invert-y-axis",          BOOLEAN,  true,    false,   true,   Dali::CameraActor::Property::INVERT_Y_AXIS         )
-DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX )
+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
 
 // calculate the far plane distance for a 16bit depth buffer with 4 bits per unit precision
-void CalculateClippingAndZ( float width, float height, float& nearClippingPlane, float& farClippingPlane, float& cameraZ )
+void CalculateClippingAndZ(float width, float height, float& nearClippingPlane, float& farClippingPlane, float& cameraZ)
 {
-  nearClippingPlane = std::max( width, height );
-  farClippingPlane = nearClippingPlane + static_cast<float>( 0xFFFF >> 4 );
-  cameraZ = 2.0f * nearClippingPlane;
+  nearClippingPlane = std::max(width, height);
+  farClippingPlane  = nearClippingPlane + static_cast<float>(0xFFFF >> 4);
+  cameraZ           = 2.0f * nearClippingPlane;
 }
 
 BaseHandle Create()
@@ -79,7 +80,7 @@ BaseHandle Create()
   return Dali::CameraActor::New();
 }
 
-TypeRegistration mType( typeid( Dali::CameraActor ), typeid( Dali::Actor ), Create );
+TypeRegistration mType(typeid(Dali::CameraActor), typeid(Dali::Actor), Create, CameraDefaultProperties);
 
 /**
  * Builds the picking ray in the world reference system from an orthographic camera
@@ -87,14 +88,14 @@ TypeRegistration mType( typeid( Dali::CameraActor ), typeid( Dali::Actor ), Crea
  * plane at the camera origin. The ray direction is the direction the camera is facing
  * (i.e. Z=-1 in view space).
  */
-void BuildOrthoPickingRay( const Matrix& viewMatrix,
-                           const Matrix& projectionMatrix,
-                           const Viewport& viewport,
-                           float screenX,
-                           float screenY,
-                           Vector4& rayOrigin,
-                           Vector4& rayDir,
-                           float nearPlaneDistance )
+void BuildOrthoPickingRay(const Matrix&   viewMatrix,
+                          const Matrix&   projectionMatrix,
+                          const Viewport& viewport,
+                          float           screenX,
+                          float           screenY,
+                          Vector4&        rayOrigin,
+                          Vector4&        rayDir,
+                          float           nearPlaneDistance)
 {
   //          inv( modelMatrix )          inv( viewMatrix )    inv( projectionMatrix )           normalize
   //          <-----------------         <-----------------         <--------------           <-------------
@@ -105,27 +106,30 @@ void BuildOrthoPickingRay( const Matrix& viewMatrix,
   //             modelMatrix                 viewMatrix             projectionMatrix             viewport
 
   // 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 );
-  if( !invViewProjection.Invert() )
+  Matrix invViewProjection(false); // Don't initialize.
+  MatrixUtils::MultiplyProjectionMatrix(invViewProjection, viewMatrix, projectionMatrix);
+  if(!invViewProjection.Invert())
   {
-    DALI_ASSERT_DEBUG( false );
+    DALI_ASSERT_DEBUG(false);
   }
 
-  Vector4 near( screenX - viewport.x, viewport.height - (screenY - viewport.y), 0.f, 1.f );
-  if( !Unproject( near, invViewProjection, viewport.width, viewport.height, rayOrigin ) )
+  Vector4 near(screenX - static_cast<float>(viewport.x),
+               static_cast<float>(viewport.height) - (screenY - static_cast<float>(viewport.y)),
+               0.f,
+               1.f);
+  if(!Unproject(near, invViewProjection, static_cast<float>(viewport.width), static_cast<float>(viewport.height), rayOrigin))
   {
-    DALI_ASSERT_DEBUG( false );
+    DALI_ASSERT_DEBUG(false);
   }
 
   Matrix invView = viewMatrix;
-  if( !invView.Invert() )
+  if(!invView.Invert())
   {
-    DALI_ASSERT_DEBUG( false );
+    DALI_ASSERT_DEBUG(false);
   }
 
-  Vector4 cameraOrigin = invView * Vector4( 0.f, 0.f, 0.f, 1.f );
-  Vector4 nearPlaneOrigin = invView * Vector4( 0.0f, 0.0f, -nearPlaneDistance, 1.0f);
+  Vector4 cameraOrigin    = invView * Vector4(0.f, 0.f, 0.f, 1.f);
+  Vector4 nearPlaneOrigin = invView * Vector4(0.0f, 0.0f, -nearPlaneDistance, 1.0f);
 
   // Vector pointing from the camera to the near plane
   rayDir = cameraOrigin - nearPlaneOrigin;
@@ -134,219 +138,397 @@ 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 CameraActor::New(const Size& size)
 {
-  CameraActorPtr actor(new CameraActor());
+  // 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();
 
-  // Second-phase construction
+  DALI_ASSERT_ALWAYS(tls && "ThreadLocalStorage is null");
 
-  actor->Initialize();
+  // Send ownership of camera.
+  AddNodeMessage(tls->GetUpdateManager(), transferOwnership);
 
-  actor->SetName("DefaultCamera");
-
-  // Create the attachment
-  actor->mCameraAttachment = CameraAttachment::New( actor->GetEventThreadServices(), *actor->mNode );
+  CameraActorPtr actor(new CameraActor(*camera));
 
-  actor->Attach(*actor->mCameraAttachment);
+  // Second-phase construction
+  actor->Initialize();
 
-  actor->SetPerspectiveProjection( size );
+  actor->SetName("DefaultCamera");
+  actor->SetPerspectiveProjection(size);
 
   // By default Actors face in the positive Z direction in world space
   // CameraActors should face in the negative Z direction, towards the other actors
-  actor->SetOrientation( Quaternion( Dali::ANGLE_180, Vector3::YAXIS ) );
+  actor->SetOrientation(Quaternion(Dali::ANGLE_180, Vector3::YAXIS));
 
   return actor;
 }
 
-void CameraActor::OnInitialize()
+CameraActor::CameraActor(const SceneGraph::Node& node)
+: Actor(Actor::BASIC, node),
+  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),
+  mInvertYAxis(SceneGraph::Camera::DEFAULT_INVERT_Y_AXIS),
+  mPropertyChanged(false)
 {
 }
 
-CameraActor::CameraActor()
-: Actor( Actor::BASIC )
+CameraActor::~CameraActor()
 {
 }
 
-CameraActor::~CameraActor()
+void CameraActor::OnSceneConnectionInternal()
 {
+  // If the canvas size has not been set, then use the size of the scene to which we've been added
+  // in order to set up the current projection
+  if(!mPropertyChanged && ((mCanvasSize.width < Math::MACHINE_EPSILON_1000) || (mCanvasSize.height < Math::MACHINE_EPSILON_1000)))
+  {
+    if(mProjectionMode == Dali::Camera::ORTHOGRAPHIC_PROJECTION)
+    {
+      SetOrthographicProjection(GetScene().GetSize());
+    }
+    else //if(mProjectionMode == Dali::Camera::PERSPECTIVE_PROJECTION)
+    {
+      SetPerspectiveProjection(GetScene().GetSize());
+    }
+  }
 }
 
-void CameraActor::SetType( Dali::Camera::Type type )
+void CameraActor::SetReflectByPlane(const Vector4& plane)
 {
-  mCameraAttachment->SetType(type);
+  SetReflectByPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), plane);
+}
+
+void CameraActor::SetTarget(const Vector3& target)
+{
+  mPropertyChanged = true;
+  if(target != mTarget) // using range epsilon
+  {
+    mTarget = target;
+
+    SetTargetPositionMessage(GetEventThreadServices(), GetCameraSceneObject(), mTarget);
+  }
+}
+
+Vector3 CameraActor::GetTarget() const
+{
+  return mTarget;
+}
+
+void CameraActor::SetType(Dali::Camera::Type type)
+{
+  if(type != mType)
+  {
+    mType = type;
+
+    // sceneObject is being used in a separate thread; queue a message to set
+    SetTypeMessage(GetEventThreadServices(), GetCameraSceneObject(), mType);
+  }
 }
 
 Dali::Camera::Type CameraActor::GetType() const
 {
-  return mCameraAttachment->GetType();
+  return mType;
 }
 
-void CameraActor::SetProjectionMode( Dali::Camera::ProjectionMode mode )
+void CameraActor::SetProjectionMode(Dali::Camera::ProjectionMode mode)
 {
-  mCameraAttachment->SetProjectionMode(mode);
+  if(mode != mProjectionMode)
+  {
+    mProjectionMode = mode;
+
+    // sceneObject is being used in a separate thread; queue a message to set
+    SetProjectionModeMessage(GetEventThreadServices(), GetCameraSceneObject(), mProjectionMode);
+  }
 }
 
 Dali::Camera::ProjectionMode CameraActor::GetProjectionMode() const
 {
-  return mCameraAttachment->GetProjectionMode();
+  return mProjectionMode;
+}
+
+void CameraActor::SetProjectionDirection(Dali::DevelCameraActor::ProjectionDirection direction)
+{
+  mPropertyChanged = true;
+  if(direction != mProjectionDirection)
+  {
+    mProjectionDirection = direction;
+
+    // sceneObject is being used in a separate thread; queue a message to set
+    SetProjectionDirectionMessage(GetEventThreadServices(), GetCameraSceneObject(), mProjectionDirection);
+  }
+}
+
+void CameraActor::SetFieldOfView(float fieldOfView)
+{
+  mPropertyChanged = true;
+  if(!Equals(fieldOfView, mFieldOfView))
+  {
+    mFieldOfView = fieldOfView;
+
+    // sceneObject is being used in a separate thread; queue a message to set
+    BakeFieldOfViewMessage(GetEventThreadServices(), GetCameraSceneObject(), mFieldOfView);
+  }
+}
+
+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::SetFieldOfView( float fieldOfView )
+void CameraActor::SetOrthographicSize(float orthographicSize)
 {
-  mCameraAttachment->SetFieldOfView(fieldOfView);
+  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::GetFieldOfView( ) const
+float CameraActor::GetOrthographicSize() const
 {
-  return mCameraAttachment->GetFieldOfView();
+  return mOrthographicSize;
 }
 
-void CameraActor::SetAspectRatio( float aspectRatio )
+float CameraActor::GetCurrentOrthographicSize() const
 {
-  mCameraAttachment->SetAspectRatio(aspectRatio);
+  // node is being used in a separate thread; copy the value from the previous update
+  return GetCameraSceneObject().GetOrthographicSize(GetEventThreadServices().GetEventBufferIndex());
 }
 
-float CameraActor::GetAspectRatio( ) const
+void CameraActor::SetAspectRatio(float aspectRatio)
 {
-  return mCameraAttachment->GetAspectRatio();
+  mPropertyChanged = true;
+  if(!Equals(aspectRatio, mAspectRatio))
+  {
+    mAspectRatio = aspectRatio;
+
+    // sceneObject is being used in a separate thread; queue a message to set
+    BakeAspectRatioMessage(GetEventThreadServices(), GetCameraSceneObject(), mAspectRatio);
+  }
 }
 
-void CameraActor::SetNearClippingPlane( float nearClippingPlane )
+float CameraActor::GetAspectRatio() const
 {
-  mCameraAttachment->SetNearClippingPlane(nearClippingPlane);
+  return mAspectRatio;
 }
 
-float CameraActor::GetNearClippingPlane( ) const
+float CameraActor::GetCurrentAspectRatio() const
 {
-  return mCameraAttachment->GetNearClippingPlane();
+  // node is being used in a separate thread; copy the value from the previous update
+  return GetCameraSceneObject().GetAspectRatio(GetEventThreadServices().GetEventBufferIndex());
 }
 
-void CameraActor::SetFarClippingPlane( float farClippingPlane )
+void CameraActor::SetNearClippingPlane(float nearClippingPlane)
 {
-  mCameraAttachment->SetFarClippingPlane(farClippingPlane);
+  mPropertyChanged = true;
+  if(!Equals(nearClippingPlane, mNearClippingPlane))
+  {
+    mNearClippingPlane = nearClippingPlane;
+
+    // sceneObject is being used in a separate thread; queue a message to set
+    SetNearClippingPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), mNearClippingPlane);
+  }
 }
 
-float CameraActor::GetFarClippingPlane( ) const
+float CameraActor::GetNearClippingPlane() const
 {
-  return mCameraAttachment->GetFarClippingPlane();
+  return mNearClippingPlane;
 }
 
-void CameraActor::SetTargetPosition(const Vector3& target)
+void CameraActor::SetFarClippingPlane(float farClippingPlane)
 {
-  mCameraAttachment->SetTargetPosition(target);
+  mPropertyChanged = true;
+  if(!Equals(farClippingPlane, mFarClippingPlane))
+  {
+    mFarClippingPlane = farClippingPlane;
+
+    // sceneObject is being used in a separate thread; queue a message to set
+    SetFarClippingPlaneMessage(GetEventThreadServices(), GetCameraSceneObject(), mFarClippingPlane);
+  }
 }
 
-Vector3 CameraActor::GetTargetPosition() const
+float CameraActor::GetFarClippingPlane() const
 {
-  return mCameraAttachment->GetTargetPosition();
+  return mFarClippingPlane;
 }
 
 void CameraActor::SetInvertYAxis(bool invertYAxis)
 {
-  mCameraAttachment->SetInvertYAxis(invertYAxis);
+  if(invertYAxis != mInvertYAxis)
+  {
+    mInvertYAxis = invertYAxis;
+
+    // sceneObject is being used in a separate thread; queue a message to set
+    SetInvertYAxisMessage(GetEventThreadServices(), GetCameraSceneObject(), mInvertYAxis);
+  }
 }
 
 bool CameraActor::GetInvertYAxis() const
 {
-  return mCameraAttachment->GetInvertYAxis();
+  return mInvertYAxis;
 }
 
-void CameraActor::SetPerspectiveProjection( const Size& size, const Vector2& stereoBias /* = Vector2::ZERO */ )
+void CameraActor::SetPerspectiveProjection(const Size& size)
 {
-  float width = size.width;
-  float height = size.height;
+  SetProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION);
+  mCanvasSize = static_cast<const Vector2>(size);
 
-  if( Size::ZERO == size )
+  if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
   {
-    StagePtr stage = Stage::GetCurrent();
-    if( stage )
+    // If the size given is invalid, i.e. ZERO, then check if we've been added to a scene
+    if(OnScene())
     {
-      const Size& stageSize = stage->GetSize();
-
-      width = stageSize.width;
-      height = stageSize.height;
+      // We've been added to a scene already, set the canvas size to the scene's size
+      mCanvasSize = GetScene().GetSize();
+    }
+    else
+    {
+      // We've not been added to a scene yet, so just return.
+      // We'll set the canvas size when we get added to a scene later
+      return;
     }
   }
+  ApplyDefaultProjection();
+}
 
-  if( ( width < Math::MACHINE_EPSILON_1000 ) || ( height < Math::MACHINE_EPSILON_1000 ) )
+void CameraActor::SetOrthographicProjection(const Size& size)
+{
+  SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
+  mCanvasSize = static_cast<const Vector2>(size);
+
+  if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
   {
-    // On the stage initialization this method is called but the size has not been set.
-    // There is no point to set any value if width or height is zero.
-    return;
+    // If the size given is invalid, i.e. ZERO, then check if we've been added to a scene
+    if(OnScene())
+    {
+      // We've been added to a scene already, set the canvas size to the scene's size
+      mCanvasSize = GetScene().GetSize();
+    }
+    else
+    {
+      // We've not been added to a scene yet, so just return.
+      // We'll set the canvas size when we get added to a scene later
+      return;
+    }
   }
 
+  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( width, height, nearClippingPlane, farClippingPlane, cameraZ );
+  CalculateClippingAndZ(width, height, nearClippingPlane, farClippingPlane, cameraZ);
+
+  // 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( height * 0.5f / cameraZ );
+  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 )
+  if(farClippingPlane < minClippingFarPlane)
   {
     farClippingPlane = minClippingFarPlane;
   }
 
   const float aspectRatio = width / height;
 
-  SetProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION);
-  SetFieldOfView( fieldOfView );
-  SetNearClippingPlane( nearClippingPlane );
-  SetFarClippingPlane( farClippingPlane );
-  SetAspectRatio( aspectRatio );
-  mCameraAttachment->SetStereoBias( stereoBias );
-  SetZ( cameraZ );
-}
-
-
-void CameraActor::SetOrthographicProjection( const Vector2& size )
-{
-  // 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 );
-}
-
-void CameraActor::SetOrthographicProjection( float left, float right, float top, float bottom, float near, float far )
-{
-  mCameraAttachment->SetLeftClippingPlane(left);
-  mCameraAttachment->SetRightClippingPlane(right);
-  mCameraAttachment->SetTopClippingPlane(top);
-  mCameraAttachment->SetBottomClippingPlane(bottom);
-  SetNearClippingPlane( near );
-  SetFarClippingPlane( far );
-  SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
+  // 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,
-                                   const Viewport& viewport,
-                                   Vector4& rayOrigin,
-                                   Vector4& rayDirection )
+bool CameraActor::BuildPickingRay(const Vector2&  screenCoordinates,
+                                  const Viewport& viewport,
+                                  Vector4&        rayOrigin,
+                                  Vector4&        rayDirection)
 {
   bool success = true;
-  if( GetProjectionMode() == Dali::Camera::PERSPECTIVE_PROJECTION )
+  if(mProjectionMode == Dali::Camera::PERSPECTIVE_PROJECTION)
   {
     // Build a picking ray in the world reference system.
     // ray starts from the camera world position
-    rayOrigin = mNode->GetWorldPosition( GetEventThreadServices().GetEventBufferIndex() );
+    rayOrigin   = GetNode().GetWorldMatrix(0).GetTranslation();
     rayOrigin.w = 1.0f;
 
     // Transform the touch point from the screen coordinate system to the world coordinates system.
-    Vector4 near( screenCoordinates.x - viewport.x, viewport.height - (screenCoordinates.y - viewport.y), 0.f, 1.f );
-    if( !Unproject( near, mCameraAttachment->GetInverseViewProjectionMatrix(), viewport.width, viewport.height, near ) )
-    {
-      // unproject failed so no picking ray possible
-      success = false;
-    }
+    Vector4       near(screenCoordinates.x - static_cast<float>(viewport.x),
+                 static_cast<float>(viewport.height) - (screenCoordinates.y - static_cast<float>(viewport.y)),
+                 0.f,
+                 1.f);
+    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.
     rayDirection.x = near.x - rayOrigin.x;
@@ -358,13 +540,14 @@ bool CameraActor::BuildPickingRay( const Vector2& screenCoordinates,
   else
   {
     float nearPlaneDistance = GetNearClippingPlane();
-    BuildOrthoPickingRay( GetViewMatrix(),
-                          GetProjectionMatrix(),
-                          viewport, screenCoordinates.x,
-                          screenCoordinates.y,
-                          rayOrigin,
-                          rayDirection,
-                          nearPlaneDistance );
+    BuildOrthoPickingRay(GetViewMatrix(),
+                         GetProjectionMatrix(),
+                         viewport,
+                         screenCoordinates.x,
+                         screenCoordinates.y,
+                         rayOrigin,
+                         rayDirection,
+                         nearPlaneDistance);
   }
 
   return success;
@@ -372,9 +555,9 @@ bool CameraActor::BuildPickingRay( const Vector2& screenCoordinates,
 
 const Matrix& CameraActor::GetViewMatrix() const
 {
-  if ( OnStage() )
+  if(OnScene())
   {
-    return mCameraAttachment->GetViewMatrix();
+    return GetCameraSceneObject().GetViewMatrix(GetEventThreadServices().GetEventBufferIndex());
   }
   else
   {
@@ -384,128 +567,27 @@ const Matrix& CameraActor::GetViewMatrix() const
 
 const Matrix& CameraActor::GetProjectionMatrix() const
 {
-  if ( OnStage() )
+  if(OnScene())
   {
-    return mCameraAttachment->GetProjectionMatrix();
+    return GetCameraSceneObject().GetProjectionMatrix(GetEventThreadServices().GetEventBufferIndex());
   }
   else
   {
     return Matrix::IDENTITY;
   }
 }
-
-unsigned int CameraActor::GetDefaultPropertyCount() const
+const SceneGraph::Camera& CameraActor::GetCameraSceneObject() const
 {
-  return Actor::GetDefaultPropertyCount() + DEFAULT_PROPERTY_COUNT;
-}
-
-void CameraActor::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
-{
-  Actor::GetDefaultPropertyIndices( indices ); // Actor class properties
-
-  indices.Reserve( indices.Size() + DEFAULT_PROPERTY_COUNT );
-
-  int index = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
-  for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i, ++index )
-  {
-    indices.PushBack( index );
-  }
-}
-
-bool CameraActor::IsDefaultPropertyWritable( Property::Index index ) const
-{
-  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
-  {
-    return Actor::IsDefaultPropertyWritable( index );
-  }
-
-  return DEFAULT_PROPERTY_DETAILS[index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX].writable;
-}
-
-bool CameraActor::IsDefaultPropertyAnimatable( Property::Index index ) const
-{
-  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
-  {
-    return Actor::IsDefaultPropertyAnimatable( index );
-  }
-
-  return DEFAULT_PROPERTY_DETAILS[index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX].animatable;
-}
-
-bool CameraActor::IsDefaultPropertyAConstraintInput( Property::Index index ) const
-{
-  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
-  {
-    return Actor::IsDefaultPropertyAConstraintInput( index );
-  }
-
-  return DEFAULT_PROPERTY_DETAILS[index - DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX].constraintInput;
-}
-
-Property::Type CameraActor::GetDefaultPropertyType( Property::Index index ) const
-{
-  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
-  {
-    return Actor::GetDefaultPropertyType( index );
-  }
-  else
-  {
-    index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
-
-    if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
-    {
-      return DEFAULT_PROPERTY_DETAILS[index].type;
-    }
-    else
-    {
-      // index out-of-bounds
-      return Property::NONE;
-    }
-  }
-}
-
-const char* CameraActor::GetDefaultPropertyName( Property::Index index ) const
-{
-  if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
-  {
-    return Actor::GetDefaultPropertyName(index);
-  }
-  else
-  {
-    index -= DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
-
-    if ( ( index >= 0 ) && ( index < DEFAULT_PROPERTY_COUNT ) )
-    {
-      return DEFAULT_PROPERTY_DETAILS[index].name;
-    }
-    return NULL;
-  }
+  return static_cast<const SceneGraph::Camera&>(GetNode());
 }
 
-Property::Index CameraActor::GetDefaultPropertyIndex(const std::string& name) const
+void CameraActor::RotateProjection(int rotationAngle)
 {
-  Property::Index index = Property::INVALID_INDEX;
-
-  // Look for name in current class' default properties
-  for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
-  {
-    if( 0 == strcmp( name.c_str(), DEFAULT_PROPERTY_DETAILS[i].name ) ) // dont want to convert rhs to string
-    {
-      index = i + DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX;
-      break;
-    }
-  }
-
-  // If not found, check in base class
-  if( Property::INVALID_INDEX == index )
-  {
-    index = Actor::GetDefaultPropertyIndex( name );
-  }
-
-  return index;
+  // sceneObject is being used in a separate thread; queue a message to set
+  RotateProjectionMessage(GetEventThreadServices(), GetCameraSceneObject(), rotationAngle);
 }
 
-void CameraActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
+void CameraActor::SetDefaultProperty(Property::Index index, const Property::Value& propertyValue)
 {
   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
   {
@@ -513,103 +595,97 @@ void CameraActor::SetDefaultProperty( Property::Index index, const Property::Val
   }
   else
   {
-    DALI_ASSERT_DEBUG(mCameraAttachment && "where is the camera?");
     switch(index)
     {
       case Dali::CameraActor::Property::TYPE:
       {
-        std::string s( propertyValue.Get<std::string>() );
-        if(s == "LOOK_AT_TARGET")
-        {
-          mCameraAttachment->SetType(Dali::Camera::LOOK_AT_TARGET);
-        }
-        else if(s == "FREE_LOOK")
-        {
-          mCameraAttachment->SetType(Dali::Camera::FREE_LOOK);
-        }
-        else
-        {
-          DALI_LOG_WARNING("Unknown camera type\n");
-        }
+        Dali::Camera::Type cameraType = Dali::Camera::Type(propertyValue.Get<int>());
+        SetType(cameraType);
         break;
       }
       case Dali::CameraActor::Property::PROJECTION_MODE:
       {
-        std::string s(propertyValue.Get<std::string>());
-        if(s == "PERSPECTIVE_PROJECTION")
-        {
-          mCameraAttachment->SetProjectionMode(Dali::Camera::PERSPECTIVE_PROJECTION);
-        }
-        else if(s == "ORTHOGRAPHIC_PROJECTION")
-        {
-          mCameraAttachment->SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
-        }
-        else
-        {
-          DALI_LOG_WARNING("Unknown projection mode\n");
-        }
+        Dali::Camera::ProjectionMode projectionMode = Dali::Camera::ProjectionMode(propertyValue.Get<int>());
+        SetProjectionMode(projectionMode);
         break;
       }
       case Dali::CameraActor::Property::FIELD_OF_VIEW:
       {
-        mCameraAttachment->SetFieldOfView(propertyValue.Get<float>());
+        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:
       {
-        mCameraAttachment->SetAspectRatio(propertyValue.Get<float>());
+        SetAspectRatio(propertyValue.Get<float>()); // set to 0 in case property is not float
         break;
       }
-      case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
       {
-        mCameraAttachment->SetLeftClippingPlane(propertyValue.Get<float>());
+        SetNearClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
         break;
       }
-      case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
       {
-        mCameraAttachment->SetRightClippingPlane(propertyValue.Get<float>());
+        SetFarClippingPlane(propertyValue.Get<float>()); // set to 0 in case property is not float
         break;
       }
-      case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
       {
-        mCameraAttachment->SetTopClippingPlane(propertyValue.Get<float>());
+        DALI_LOG_WARNING("LEFT_PLANE_DISTANCE is read-only\n");
         break;
       }
-      case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
       {
-        mCameraAttachment->SetBottomClippingPlane(propertyValue.Get<float>());
+        DALI_LOG_WARNING("RIGHT_PLANE_DISTANCE is read-only\n");
         break;
       }
-      case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
       {
-        mCameraAttachment->SetNearClippingPlane(propertyValue.Get<float>());
+        DALI_LOG_WARNING("TOP_PLANE_DISTANCE is read-only\n");
         break;
       }
-      case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
       {
-        mCameraAttachment->SetFarClippingPlane(propertyValue.Get<float>());
+        DALI_LOG_WARNING("BOTTOM_PLANE_DISTANCE is read-only\n");
         break;
       }
       case Dali::CameraActor::Property::TARGET_POSITION:
       {
-        mCameraAttachment->SetTargetPosition(propertyValue.Get<Vector3>());
+        SetTarget(propertyValue.Get<Vector3>()); // set to 0 in case property is not Vector3
         break;
       }
       case Dali::CameraActor::Property::PROJECTION_MATRIX:
       {
-        DALI_LOG_WARNING("projection-matrix property is not animatable \n");
+        DALI_LOG_WARNING("projection-matrix is read-only\n");
         break;
       }
       case Dali::CameraActor::Property::VIEW_MATRIX:
       {
-        DALI_LOG_WARNING("view-matrix property is not animatable \n");
+        DALI_LOG_WARNING("view-matrix is read-only\n");
         break;
       }
       case Dali::CameraActor::Property::INVERT_Y_AXIS:
       {
-        mCameraAttachment->SetInvertYAxis(propertyValue.Get<bool>());
+        SetInvertYAxis(propertyValue.Get<bool>()); // set to false in case property is not bool
+        break;
+      }
+      case Dali::DevelCameraActor::Property::REFLECTION_PLANE:
+      {
+        SetReflectByPlane(propertyValue.Get<Vector4>());
+        break;
+      }
+      case Dali::DevelCameraActor::Property::PROJECTION_DIRECTION:
+      {
+        Dali::DevelCameraActor::ProjectionDirection projectionDirection = Dali::DevelCameraActor::ProjectionDirection(propertyValue.Get<int>());
+        SetProjectionDirection(projectionDirection);
         break;
       }
+
       default:
       {
         DALI_LOG_WARNING("Unknown property (%d)\n", index);
@@ -620,7 +696,7 @@ void CameraActor::SetDefaultProperty( Property::Index index, const Property::Val
   } // else
 }
 
-Property::Value CameraActor::GetDefaultProperty( Property::Index index ) const
+Property::Value CameraActor::GetDefaultProperty(Property::Index index) const
 {
   Property::Value ret;
   if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
@@ -629,106 +705,86 @@ Property::Value CameraActor::GetDefaultProperty( Property::Index index ) const
   }
   else
   {
-    DALI_ASSERT_DEBUG(mCameraAttachment && "where is the camera?");
     switch(index)
     {
       case Dali::CameraActor::Property::TYPE:
       {
-        if(mCameraAttachment->GetType() == Dali::Camera::LOOK_AT_TARGET)
-        {
-          ret = "LOOK_AT_TARGET";
-        }
-        else if(mCameraAttachment->GetType() == Dali::Camera::FREE_LOOK)
-        {
-          ret = "FREE_LOOK";
-        }
-        else
-        {
-          ret = "";
-          DALI_ASSERT_DEBUG("Unknown camera type\n");
-        }
+        ret = mType;
         break;
       }
       case Dali::CameraActor::Property::PROJECTION_MODE:
       {
-        if(mCameraAttachment->GetProjectionMode() == Dali::Camera::PERSPECTIVE_PROJECTION)
-        {
-          ret = "PERSPECTIVE_PROJECTION";
-        }
-        else if(mCameraAttachment->GetProjectionMode() == Dali::Camera::ORTHOGRAPHIC_PROJECTION)
-        {
-          ret = "ORTHOGRAPHIC_PROJECTION";
-        }
-        else
-        {
-          ret = "";
-          DALI_ASSERT_DEBUG("Unknown projection mode\n");
-        }
+        ret = mProjectionMode;
         break;
       }
       case Dali::CameraActor::Property::FIELD_OF_VIEW:
       {
-        ret = mCameraAttachment->GetFieldOfView();
+        ret = mFieldOfView;
+        break;
+      }
+      case Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE:
+      {
+        ret = mOrthographicSize;
         break;
       }
       case Dali::CameraActor::Property::ASPECT_RATIO:
       {
-        ret = mCameraAttachment->GetAspectRatio();
+        ret = mAspectRatio;
         break;
       }
-      case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
       {
-        ret = mCameraAttachment->GetLeftClippingPlane();
+        ret = mNearClippingPlane;
         break;
       }
-      case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
       {
-        ret = mCameraAttachment->GetRightClippingPlane();
+        ret = mFarClippingPlane;
         break;
       }
-      case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::LEFT_PLANE_DISTANCE:
       {
-        ret = mCameraAttachment->GetTopClippingPlane();
+        ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).LeftPlaneDistance();
         break;
       }
-      case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE:
       {
-        ret = mCameraAttachment->GetBottomClippingPlane();
+        ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).RightPlaneDistance();
         break;
       }
-      case Dali::CameraActor::Property::NEAR_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::TOP_PLANE_DISTANCE:
       {
-        ret = mCameraAttachment->GetNearClippingPlane();
+        ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).TopPlaneDistance();
         break;
       }
-      case Dali::CameraActor::Property::FAR_PLANE_DISTANCE:
+      case Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE:
       {
-        ret = mCameraAttachment->GetFarClippingPlane();
+        ret = OrthographicSizeConverter(mOrthographicSize, mAspectRatio, mProjectionDirection).BottomPlaneDistance();
         break;
       }
       case Dali::CameraActor::Property::TARGET_POSITION:
       {
-        ret = mCameraAttachment->GetTargetPosition();
+        ret = mTarget;
         break;
       }
       case Dali::CameraActor::Property::PROJECTION_MATRIX:
       {
-        ret = mCameraAttachment->GetProjectionMatrix();
+        ret = GetProjectionMatrix(); // Only on scene-graph
         break;
       }
       case Dali::CameraActor::Property::VIEW_MATRIX:
       {
-        ret = mCameraAttachment->GetViewMatrix();
+        ret = GetViewMatrix(); // Only on scene-graph
         break;
       }
       case Dali::CameraActor::Property::INVERT_Y_AXIS:
       {
-        ret = mCameraAttachment->GetInvertYAxis();
+        ret = mInvertYAxis;
         break;
       }
-      default:
+      case Dali::DevelCameraActor::Property::PROJECTION_DIRECTION:
       {
-        DALI_LOG_WARNING("Unknown property (%d)\n", index);
+        ret = mProjectionDirection;
         break;
       }
     } // switch(index)
@@ -737,65 +793,205 @@ Property::Value CameraActor::GetDefaultProperty( Property::Index index ) const
   return ret;
 }
 
-const SceneGraph::PropertyBase* CameraActor::GetSceneObjectAnimatableProperty( Property::Index index ) const
+Property::Value CameraActor::GetDefaultPropertyCurrentValue(Property::Index index) const
 {
-  DALI_ASSERT_ALWAYS( IsPropertyAnimatable(index) && "Property is not animatable" );
-
-  const SceneGraph::PropertyBase* property( NULL );
-
-  // This method should only return a property of an object connected to the scene-graph
-  if ( !OnStage() )
+  Property::Value ret;
+  if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
   {
-    return property;
+    ret = Actor::GetDefaultPropertyCurrentValue(index);
   }
-
-  // let actor handle animatable properties, we have no animatable properties
-  if( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT )
+  else
   {
-    property = Actor::GetSceneObjectAnimatableProperty(index);
+    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 property;
+  return ret;
 }
 
-const PropertyInputImpl* CameraActor::GetSceneObjectInputProperty( Property::Index index ) const
+void CameraActor::OnNotifyDefaultPropertyAnimation(Animation& animation, Property::Index index, const Property::Value& value, Animation::Type animationType)
 {
-  const PropertyInputImpl* property( NULL );
-
-  // This method should only return a property of an object connected to the scene-graph
-  if ( !OnStage() )
-  {
-    return property;
-  }
-
-  // if its an actor default property or a custom property (actor already handles custom properties)
-  if( ( index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT ) || ( index >= DEFAULT_PROPERTY_MAX_COUNT ) )
+  if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
   {
-    property = Actor::GetSceneObjectInputProperty(index);
+    Actor::OnNotifyDefaultPropertyAnimation(animation, index, value, animationType);
   }
   else
   {
-    switch( index )
+    switch(animationType)
     {
-      case Dali::CameraActor::Property::PROJECTION_MATRIX:
+      case Animation::TO:
+      case Animation::BETWEEN:
       {
-        property = mCameraAttachment->GetProjectionMatrixProperty();
+        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 Dali::CameraActor::Property::VIEW_MATRIX:
+      case Animation::BY:
       {
-        property = mCameraAttachment->GetViewMatrixProperty();
+        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;
       }
-      default:
-        DALI_LOG_WARNING("Not an input property (%d)\n", index);
-        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 = GetCameraSceneObject().GetProjectionMatrix();
+      break;
+    }
+    case Dali::CameraActor::Property::VIEW_MATRIX:
+    {
+      property = GetCameraSceneObject().GetViewMatrix();
+      break;
+    }
+      // no default on purpose as we chain method up to actor
+  }
+  if(!property)
+  {
+    property = Actor::GetSceneObjectInputProperty(index);
+  }
 
   return property;
 }
 
+void CameraActor::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
+{
+  // If Position or Orientation are explicitly set, make mPropertyChanged flag true.
+  if(index == Dali::Actor::Property::POSITION ||
+     index == Dali::Actor::Property::POSITION_X ||
+     index == Dali::Actor::Property::POSITION_Y ||
+     index == Dali::Actor::Property::POSITION_Z ||
+     index == Dali::Actor::Property::ORIENTATION)
+  {
+    mPropertyChanged = true;
+  }
+}
 
 } // namespace Internal