Changed STEREO_HORIZONTAL view mode to work with landscape orientation 09/25709/5
authorFerran Sole <ferran.sole@samsung.com>
Fri, 8 Aug 2014 13:03:00 +0000 (14:03 +0100)
committerFerran Sole <ferran.sole@samsung.com>
Tue, 12 Aug 2014 09:42:19 +0000 (10:42 +0100)
On Stereo horizontal mode, the left and right images are now rendered to be viewed in landscape mode
preserving aspect ratio. Also fixed bug which caused to incorrectly reuse render list when camera was
different to the one used to update the render list before.

To set STEREO_HORIZONTAL mode, use '--view 1' as a command-line argument.

Change-Id: I7943b31bc6349c2a70244e86b4b0762e6bdb7ea0

12 files changed:
dali/internal/event/actor-attachments/camera-attachment-impl.cpp
dali/internal/event/actor-attachments/camera-attachment-impl.h
dali/internal/event/actors/camera-actor-impl.cpp
dali/internal/event/actors/camera-actor-impl.h
dali/internal/event/common/stage-impl.cpp
dali/internal/update/manager/prepare-render-instructions.cpp
dali/internal/update/node-attachments/scene-graph-camera-attachment.cpp
dali/internal/update/node-attachments/scene-graph-camera-attachment.h
dali/internal/update/nodes/scene-graph-layer.cpp
dali/internal/update/nodes/scene-graph-layer.h
dali/internal/update/render-tasks/scene-graph-render-task.cpp
dali/internal/update/render-tasks/scene-graph-render-task.h

index 45e2e9e..767f848 100644 (file)
@@ -55,13 +55,13 @@ CameraAttachment::CameraAttachment( Stage& stage )
   mInvertYAxis( SceneGraph::CameraAttachment::DEFAULT_INVERT_Y_AXIS ),
   mFieldOfView( SceneGraph::CameraAttachment::DEFAULT_FIELD_OF_VIEW ),
   mAspectRatio( SceneGraph::CameraAttachment::DEFAULT_ASPECT_RATIO ),
-  mStereoBias( SceneGraph::CameraAttachment::DEFAULT_STEREO_BIAS ),
   mLeftClippingPlane( SceneGraph::CameraAttachment::DEFAULT_LEFT_CLIPPING_PLANE ),
   mRightClippingPlane( SceneGraph::CameraAttachment::DEFAULT_RIGHT_CLIPPING_PLANE ),
   mTopClippingPlane( SceneGraph::CameraAttachment::DEFAULT_TOP_CLIPPING_PLANE ),
   mBottomClippingPlane( SceneGraph::CameraAttachment::DEFAULT_BOTTOM_CLIPPING_PLANE ),
   mNearClippingPlane( SceneGraph::CameraAttachment::DEFAULT_NEAR_CLIPPING_PLANE ),
   mFarClippingPlane( SceneGraph::CameraAttachment::DEFAULT_FAR_CLIPPING_PLANE ),
+  mStereoBias( SceneGraph::CameraAttachment::DEFAULT_STEREO_BIAS ),
   mTargetPosition( SceneGraph::CameraAttachment::DEFAULT_TARGET_POSITION )
 {
 }
@@ -139,9 +139,9 @@ float CameraAttachment::GetAspectRatio() const
   return mAspectRatio;
 }
 
-void CameraAttachment::SetStereoBias(float stereoBias)
+void CameraAttachment::SetStereoBias(const Vector2& stereoBias)
 {
-  if( ! Equals(stereoBias, mStereoBias) )
+  if( ! Equals(stereoBias.x, mStereoBias.x ) || ! Equals(stereoBias.y, mStereoBias.y )  )
   {
     mStereoBias = stereoBias;
 
@@ -150,7 +150,7 @@ void CameraAttachment::SetStereoBias(float stereoBias)
   }
 }
 
-float CameraAttachment::GetStereoBias(float stereoBias) const
+Vector2 CameraAttachment::GetStereoBias() const
 {
   return mStereoBias;
 }
index 11c24a6..110f569 100644 (file)
@@ -114,13 +114,13 @@ public:
    * @copydoc Dali::Camera::SetLeftClippingPlane * Set stereo bias. The frustum offset for a 3D camera
    * @param[in] stereoBias The frustum offset for the 3D camera
    */
-  void SetStereoBias(float stereoBias);
+  void SetStereoBias(const Vector2& stereoBias);
 
   /**
    * Get stereo bias. The frustum offset for a 3D camera
    * @return The frustum offset for the 3D camera
    */
-  float GetStereoBias(float stereoBias) const;
+  Vector2 GetStereoBias() const;
 
   /**
    * @copydoc Dali::Camera::SetLeftClippingPlane
@@ -281,13 +281,13 @@ private:
   bool               mInvertYAxis;
   float              mFieldOfView;
   float              mAspectRatio;
-  float              mStereoBias;
   float              mLeftClippingPlane;
   float              mRightClippingPlane;
   float              mTopClippingPlane;
   float              mBottomClippingPlane;
   float              mNearClippingPlane;
   float              mFarClippingPlane;
+  Vector2            mStereoBias;
   Vector3            mTargetPosition;
 };
 
index 95f397e..f952f47 100644 (file)
@@ -292,7 +292,7 @@ bool CameraActor::GetInvertYAxis() const
   return mCameraAttachment->GetInvertYAxis();
 }
 
-void CameraActor::SetPerspectiveProjection( const Size& size, float stereoBias /* = 0.0f */ )
+void CameraActor::SetPerspectiveProjection( const Size& size, const Vector2& stereoBias /* = Vector2::ZERO */ )
 {
   float width = size.width;
   float height = size.height;
index 3e7ab6f..780fab7 100644 (file)
@@ -145,9 +145,9 @@ public:
 
   /**
    * @copydoc Dali::CameraActor::SetPerspectiveProjection()
-   * @param[in] stereoBias The frustum horizontal offset for stereoscopic cameras
+   * @param[in] stereoBias The frustum horizontal and vertical offset for stereoscopic cameras
    */
-  void SetPerspectiveProjection( const Size& size, float stereoBias = 0.0f );
+  void SetPerspectiveProjection( const Size& size, const Vector2& stereoBias = Vector2::ZERO );
 
   /**
    * @copydoc Dali::CameraActor::SetOrthographicProjection(const Vector2& size);
index 7e49d72..88fd061 100644 (file)
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <algorithm>
+#include <cmath>
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/system-overlay.h>
@@ -263,28 +264,26 @@ void Stage::SetViewMode( ViewMode viewMode )
   {
     DALI_LOG_INFO( Debug::Filter::gActor, Debug::Concise, "View mode changed from %d to %d\n", mViewMode, viewMode);
 
-    const float stereoBase( ( (mStereoBase / 25.4f) * GetDpi().x ) * 0.5f );
-
     if( mViewMode == MONO )
     {
       mDefaultCamera->SetRotation( Degree( 180.0f ), Vector3::YAXIS );
       mRenderTaskList->GetTask(0).SetSourceActor( Dali::Actor() );
 
+      //Create camera and RenderTask for left eye
       mLeftCamera = CameraActor::New( Size::ZERO );
       mLeftCamera->SetParentOrigin( ParentOrigin::CENTER );
-      mLeftCamera->SetPerspectiveProjection( mSize, stereoBase );
-      mLeftCamera->SetPosition( Vector3( stereoBase, 0.0f, 0.0f ) );
       mDefaultCamera->Add( *mLeftCamera.Get() );
       mLeftRenderTask = mRenderTaskList->CreateTask();
       mLeftRenderTask.SetCameraActor( Dali::CameraActor( mLeftCamera.Get() ) );
       mLeftCamera->SetType( Dali::Camera::FREE_LOOK );
 
+      //Create camera and RenderTask for right eye
       mRightCamera = CameraActor::New( Size::ZERO );
       mRightCamera->SetParentOrigin( ParentOrigin::CENTER );
-      mRightCamera->SetPerspectiveProjection( mSize, -stereoBase );
-      mRightCamera->SetPosition( Vector3( -stereoBase, 0.0f, 0.0f ) );
       mDefaultCamera->Add( *mRightCamera.Get() );
       mRightRenderTask = mRenderTaskList->CreateTask();
+      mRightRenderTask.SetClearColor( Vector4( 1.0f,0.0f,0.0f,1.0f));
+
       mRightRenderTask.SetCameraActor( Dali::CameraActor( mRightCamera.Get() ) );
       mRightCamera->SetType( Dali::Camera::FREE_LOOK );
     }
@@ -309,18 +308,54 @@ void Stage::SetViewMode( ViewMode viewMode )
         mDefaultCamera->SetRotation( Degree( 0.0f ), Vector3::YAXIS );
         mDefaultCamera->SetType( Dali::Camera::LOOK_AT_TARGET );
         mRenderTaskList->GetTask(0).SetSourceActor( Dali::Layer(mRootLayer.Get()) );
+
         break;
       }
       case STEREO_HORIZONTAL:
       {
-        mLeftRenderTask.SetViewport( Viewport(0, 0, mSize.width, mSize.height * 0.5f ) );
-        mRightRenderTask.SetViewport( Viewport(0, mSize.height * 0.5f, mSize.width, mSize.height * 0.5f) );
+        //Stereo mode with horizontal split is for landscape mode. That's the reason for the cameras being rotated
+        //Top camera renders the scene as seen from the right eye and bottom camera as seen from left.
+
+        //Calculate separation in pixels along vertical axis ( mStereoBase is defined in millimetres )
+        const float stereoBase( ( (mStereoBase / 25.4f) * GetDpi().y ) * 0.5f );
+
+        //Calculate aspect ratio
+        float aspect = mSize.width / (mSize.height * 0.5f);
+
+        mLeftCamera->SetPerspectiveProjection( mSize, Vector2( 0.0f,stereoBase) );
+        mLeftCamera->SetAspectRatio( aspect );
+        mLeftCamera->SetRotation( Degree(-90.0f), Vector3::ZAXIS );
+        mLeftCamera->SetPosition( Vector3( stereoBase, 0.0f, 0.0f ) );
+        mLeftRenderTask.SetViewport( Viewport(0, mSize.height * 0.5f, mSize.width, mSize.height * 0.5f) );
+
+        mRightCamera->SetPerspectiveProjection( mSize, Vector2( 0.0,  -stereoBase) );
+        mRightCamera->SetAspectRatio( aspect );
+        mRightCamera->SetRotation( Degree(-90.0f), Vector3::ZAXIS );
+        mRightCamera->SetPosition( Vector3(-stereoBase, 0.0f, 0.0f ) );
+        mRightRenderTask.SetViewport( Viewport(0, 0, mSize.width, mSize.height * 0.5f ) );
+
         break;
       }
       case STEREO_VERTICAL:
       {
+        //Calculate separation in pixels along horizontal axis
+        const float stereoBase( ( (mStereoBase / 25.4f) * GetDpi().x ) * 0.5f );
+
+        //Recalculate fov based on viewport size
+        const float fov = 2.0f * std::atan(  mSize.y / (2.0f * std::max( mSize.x*0.5f, mSize.y )) );
+
+        mLeftCamera->SetPerspectiveProjection( Size( mSize.x * 0.5f, mSize.y ), Vector2(stereoBase,0.0f) );
+        mLeftCamera->SetFieldOfView( fov );
+        mLeftCamera->SetRotation( Degree(0.0f), Vector3::ZAXIS );
+        mLeftCamera->SetPosition( Vector3( stereoBase, 0.0f, 0.0f ) );
         mLeftRenderTask.SetViewport( Viewport(0, 0, mSize.width * 0.5f, mSize.height ) );
+
+        mRightCamera->SetPerspectiveProjection( Size( mSize.x * 0.5f, mSize.y ), Vector2(-stereoBase,0.0f) );
+        mRightCamera->SetFieldOfView( fov );
+        mRightCamera->SetRotation( Degree(0.0f), Vector3::ZAXIS );
+        mRightCamera->SetPosition( Vector3( -stereoBase, 0.0f, 0.0f ) );
         mRightRenderTask.SetViewport( Viewport(mSize.width * 0.5f, 0, mSize.width * 0.5f, mSize.height ) );
+
         break;
       }
       case STEREO_INTERLACED:
@@ -343,13 +378,40 @@ void Stage::SetStereoBase( float stereoBase )
     DALI_LOG_INFO( Debug::Filter::gActor, Debug::Concise, "old( %.2f) new(%.2f)", mStereoBase, stereoBase );
     mStereoBase = stereoBase;
 
-    if( mViewMode != MONO )
+    switch( mViewMode  )
     {
-      stereoBase *= 0.5f;
-      mLeftCamera->SetX( stereoBase );
-      mLeftCamera->SetPerspectiveProjection( mSize, stereoBase );
-      mRightCamera->SetX( -stereoBase );
-      mRightCamera->SetPerspectiveProjection( mSize, -stereoBase );
+      case STEREO_VERTICAL:
+      {
+        stereoBase = mStereoBase / 25.4f * GetDpi().y * 0.5f;
+        float aspect = mSize.width / (mSize.height * 0.5f);
+
+        mLeftCamera->SetPerspectiveProjection( mSize, Vector2( 0.0, stereoBase) );
+        mLeftCamera->SetAspectRatio( aspect );
+        mLeftCamera->SetX( stereoBase );
+
+        mRightCamera->SetPerspectiveProjection( mSize, Vector2( 0.0, -stereoBase) );
+        mRightCamera->SetAspectRatio( aspect );
+        mRightCamera->SetX( -stereoBase );
+
+        break;
+      }
+      case STEREO_HORIZONTAL:
+      {
+        stereoBase = mStereoBase / 25.4f * GetDpi().x * 0.5f;
+        const float fov = 2.0f * std::atan(  mSize.y / (2.0f * std::max( mSize.x*0.5f, mSize.y )) );
+
+        mLeftCamera->SetPerspectiveProjection( Size( mSize.x * 0.5f, mSize.y ), Vector2(stereoBase,0.0f) );
+        mLeftCamera->SetFieldOfView( fov );
+        mLeftCamera->SetX( stereoBase );
+
+        mRightCamera->SetPerspectiveProjection( Size( mSize.x * 0.5f, mSize.y ), Vector2(-stereoBase,0.0f) );
+        mRightCamera->SetFieldOfView( fov );
+        mRightCamera->SetX( -stereoBase );
+
+        break;
+      }
+      default:
+        break;
     }
   }
 }
index c23be8c..bae7711 100644 (file)
@@ -468,7 +468,7 @@ void PrepareRenderInstruction( BufferIndex updateBufferIndex,
     const bool opaqueRenderablesExist( !layer.opaqueRenderables.empty() );
     const bool transparentRenderablesExist( !layer.transparentRenderables.empty() );
     const bool overlayRenderablesExist( !layer.overlayRenderables.empty() );
-    const bool tryReuseRenderList( layer.CanReuseRenderers() && viewMatrixHasNotChanged );
+    const bool tryReuseRenderList( viewMatrixHasNotChanged && layer.CanReuseRenderers(renderTask.GetCamera()) );
 
     // Ignore stencils if there's nothing to test
     if( stencilRenderablesExist &&
index 7a1572f..868ae59 100644 (file)
@@ -91,13 +91,13 @@ void Frustum(Matrix& result, float left, float right, float bottom, float top, f
   m[12] = m[13] = m[15] = 0.0f;
 }
 
-void Perspective(Matrix& result, float fovy, float aspect, float near, float far, bool invertYAxis, float stereoBias )
+void Perspective(Matrix& result, float fovy, float aspect, float near, float far, bool invertYAxis, const Vector2& stereoBias )
 {
   float frustumH = tanf( fovy * 0.5f ) * near;
   float frustumW = frustumH * aspect;
-  float bias = stereoBias * 0.5f;
+  Vector2 bias = stereoBias * 0.5f;
 
-  Frustum(result, -(frustumW + bias), frustumW - bias, -frustumH, frustumH, near, far, invertYAxis);
+  Frustum(result, -(frustumW + bias.x), frustumW - bias.x, -(frustumH + bias.y), frustumH - bias.y, near, far, invertYAxis);
 }
 
 void Orthographic(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis)
@@ -141,13 +141,13 @@ const Dali::Camera::ProjectionMode CameraAttachment::DEFAULT_MODE( Dali::Camera:
 const bool  CameraAttachment::DEFAULT_INVERT_Y_AXIS( false );
 const float CameraAttachment::DEFAULT_FIELD_OF_VIEW( 45.0f*(M_PI/180.0f) );
 const float CameraAttachment::DEFAULT_ASPECT_RATIO( 4.0f/3.0f );
-const float CameraAttachment::DEFAULT_STEREO_BIAS( 0.0f );
 const float CameraAttachment::DEFAULT_LEFT_CLIPPING_PLANE(-240.0f);
 const float CameraAttachment::DEFAULT_RIGHT_CLIPPING_PLANE(240.0f);
 const float CameraAttachment::DEFAULT_TOP_CLIPPING_PLANE(-400.0f);
 const float CameraAttachment::DEFAULT_BOTTOM_CLIPPING_PLANE(400.0f);
 const float CameraAttachment::DEFAULT_NEAR_CLIPPING_PLANE( 800.0f ); // default height of the screen
 const float CameraAttachment::DEFAULT_FAR_CLIPPING_PLANE( DEFAULT_NEAR_CLIPPING_PLANE + 2.f * DEFAULT_NEAR_CLIPPING_PLANE );
+const Vector2 CameraAttachment::DEFAULT_STEREO_BIAS( 0.0f, 0.0f );
 const Vector3 CameraAttachment::DEFAULT_TARGET_POSITION( 0.0f, 0.0f, 0.0f );
 
 
@@ -160,13 +160,13 @@ CameraAttachment::CameraAttachment()
   mInvertYAxis( DEFAULT_INVERT_Y_AXIS ),
   mFieldOfView( DEFAULT_FIELD_OF_VIEW ),
   mAspectRatio( DEFAULT_ASPECT_RATIO ),
-  mStereoBias( DEFAULT_STEREO_BIAS ),
   mLeftClippingPlane( DEFAULT_LEFT_CLIPPING_PLANE ),
   mRightClippingPlane( DEFAULT_RIGHT_CLIPPING_PLANE ),
   mTopClippingPlane( DEFAULT_TOP_CLIPPING_PLANE ),
   mBottomClippingPlane( DEFAULT_BOTTOM_CLIPPING_PLANE ),
   mNearClippingPlane( DEFAULT_NEAR_CLIPPING_PLANE ),
   mFarClippingPlane( DEFAULT_FAR_CLIPPING_PLANE ),
+  mStereoBias( DEFAULT_STEREO_BIAS ),
   mTargetPosition( DEFAULT_TARGET_POSITION ),
   mViewMatrix( Matrix::IDENTITY ),
   mProjectionMatrix( Matrix::IDENTITY ),
@@ -227,7 +227,7 @@ void CameraAttachment::SetAspectRatio( float aspectRatio )
   mUpdateProjectionFlag = UPDATE_COUNT;
 }
 
-void CameraAttachment::SetStereoBias( float stereoBias )
+void CameraAttachment::SetStereoBias( const Vector2& stereoBias )
 {
   mStereoBias = stereoBias;
   mUpdateProjectionFlag = UPDATE_COUNT;
index 088c293..d27e13b 100644 (file)
@@ -57,13 +57,13 @@ public:
   static const bool  DEFAULT_INVERT_Y_AXIS;
   static const float DEFAULT_FIELD_OF_VIEW;
   static const float DEFAULT_ASPECT_RATIO;
-  static const float DEFAULT_STEREO_BIAS;
   static const float DEFAULT_LEFT_CLIPPING_PLANE;
   static const float DEFAULT_RIGHT_CLIPPING_PLANE;
   static const float DEFAULT_TOP_CLIPPING_PLANE;
   static const float DEFAULT_BOTTOM_CLIPPING_PLANE;
   static const float DEFAULT_NEAR_CLIPPING_PLANE;
   static const float DEFAULT_FAR_CLIPPING_PLANE;
+  static const Vector2 DEFAULT_STEREO_BIAS;
   static const Vector3 DEFAULT_TARGET_POSITION;
 
   /**
@@ -121,7 +121,7 @@ public:
   /**
    * @copydoc Dali::Internal::CameraAttachment::SetStereoBias
    */
-  void SetStereoBias(float stereoBias);
+  void SetStereoBias(const Vector2& stereoBias);
 
    /**
    * @copydoc Dali::Internal::CameraAttachment::SetLeftClippingPlane
@@ -246,13 +246,13 @@ public:  // PROPERTIES
 
   float                         mFieldOfView;
   float                         mAspectRatio;
-  float                         mStereoBias;
   float                         mLeftClippingPlane;
   float                         mRightClippingPlane;
   float                         mTopClippingPlane;
   float                         mBottomClippingPlane;
   float                         mNearClippingPlane;
   float                         mFarClippingPlane;
+  Vector2                       mStereoBias;
   Vector3                       mTargetPosition;
 
   InheritedProperty<Matrix>     mViewMatrix;           ///< The view-matrix; this is double buffered for input handling.
@@ -309,9 +309,9 @@ inline void SetAspectRatioMessage( EventToUpdate& eventToUpdate, const CameraAtt
   new (slot) LocalType( &attachment, &CameraAttachment::SetAspectRatio, parameter );
 }
 
-inline void SetStereoBiasMessage( EventToUpdate& eventToUpdate, const CameraAttachment& attachment, float parameter )
+inline void SetStereoBiasMessage( EventToUpdate& eventToUpdate, const CameraAttachment& attachment, const Vector2& parameter )
 {
-  typedef MessageValue1< CameraAttachment, float > LocalType;
+  typedef MessageValue1< CameraAttachment, Vector2 > LocalType;
 
   // Reserve some memory inside the message queue
   unsigned int* slot = eventToUpdate.ReserveMessageSlot( sizeof( LocalType ) );
index cc99243..3d0e5e5 100644 (file)
@@ -41,6 +41,7 @@ SceneGraph::Layer* Layer::New()
 Layer::Layer()
 : mSortFunction( Dali::Layer::ZValue ),
   mClippingBox( 0,0,0,0 ),
+  mLastCamera(0),
   mIsClipping( false ),
   mDepthTestDisabled( false ),
   mIsDefaultSortFunction( true )
index b7d870f..731f96e 100644 (file)
@@ -142,11 +142,19 @@ public:
   }
 
   /**
-   * @return True if all children have been clean for two consequtive frames
+   * Checks if it is ok to reuse renderers. Renderers can be reused if ModelView transform for all the renderers
+   * has not changed from previous use.
+   * @param[in] camera A pointer to the camera that we want to use to render the list.
+   * @return True if all children transforms have been clean for two consecutive frames and the camera we are going
+   * to use is the same than the one used before ( Otherwise View transform will be different )
+   *
    */
-  bool CanReuseRenderers()
+  bool CanReuseRenderers(Node* camera)
   {
-    return mAllChildTransformsClean[ 0 ] && mAllChildTransformsClean[ 1 ];
+    bool bReturn( mAllChildTransformsClean[ 0 ] && mAllChildTransformsClean[ 1 ] && camera == mLastCamera );
+    mLastCamera = camera;
+
+    return bReturn;
   }
 
   /**
@@ -183,6 +191,8 @@ private:
   SortFunctionType mSortFunction; ///< Used to sort semi-transparent geometry
 
   ClippingBox mClippingBox;           ///< The clipping box, in window coordinates
+  Node* mLastCamera;                  ///< Pointer to the last camera that has rendered the layer
+
   bool mAllChildTransformsClean[ 2 ]; ///< True if all child nodes transforms are clean,
                                       /// double buffered as we need two clean frames before we can reuse N-1 for N+1
                                       /// this allows us to cache render items when layer is "static"
index 27acf09..4fa7e21 100644 (file)
@@ -487,6 +487,11 @@ bool RenderTask::GetViewportEnabled( BufferIndex bufferIndex ) const
   return false;
 }
 
+Node* RenderTask::GetCamera() const
+{
+  return mCameraNode;
+}
+
 void RenderTask::ResetDefaultProperties( BufferIndex updateBufferIndex )
 {
   // Reset default properties
index 3cdf32a..e178be2 100644 (file)
@@ -302,6 +302,11 @@ public:
    */
   void SetCompleteStatusManager( CompleteStatusManager* completeStatusManager );
 
+  /**
+   * @return A pointer to the camera used by the RenderTask
+   */
+  Node* GetCamera() const;
+
 private:
 
   /**