Implementation of reflection feature 10/224310/11
authoradam.b <adam.b@samsung.com>
Fri, 7 Feb 2020 17:49:41 +0000 (17:49 +0000)
committeradam.b <adam.b@samsung.com>
Fri, 20 Mar 2020 15:44:06 +0000 (15:44 +0000)
Change-Id: I63e4e1d46acb7af7bd382d7e1c6f0b5e615a99db

12 files changed:
automated-tests/src/dali/utc-Dali-CameraActor.cpp
dali/devel-api/actors/camera-actor-devel.h [new file with mode: 0644]
dali/devel-api/file.list
dali/internal/event/actors/camera-actor-impl.cpp
dali/internal/event/actors/camera-actor-impl.h
dali/internal/render/common/render-algorithms.cpp
dali/internal/render/common/render-algorithms.h
dali/internal/render/common/render-instruction.h
dali/internal/render/renderers/render-renderer.cpp
dali/internal/render/renderers/render-renderer.h
dali/internal/update/render-tasks/scene-graph-camera.cpp
dali/internal/update/render-tasks/scene-graph-camera.h

index de0cb29..85d6465 100644 (file)
@@ -21,7 +21,7 @@
 #include <cmath>
 #include <dali/public-api/dali-core.h>
 #include <dali/devel-api/actors/actor-devel.h>
-
+#include <dali/devel-api/actors/camera-actor-devel.h>
 
 #include "dali-test-suite-utils/dali-test-suite-utils.h"
 
@@ -1738,3 +1738,61 @@ int UtcDaliCameraActorCheckLookAtAndFreeLookViews03(void)
   }
   END_TEST;
 }
+
+int UtcDaliCameraActorReflectionByPlane(void)
+{
+  TestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  Vector3 targetPosition( Vector3::ZERO );
+  Vector3 cameraOffset( 0.0f, 100.0f, 100.0f );
+
+  CameraActor freeLookCameraActor = stage.GetRenderTaskList().GetTask(0).GetCameraActor();
+  freeLookCameraActor.SetType(Camera::LOOK_AT_TARGET);
+  freeLookCameraActor.SetTargetPosition( targetPosition );
+  freeLookCameraActor.SetPosition(cameraOffset);
+
+  stage.GetRootLayer().SetPosition( 1, 0 );
+
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+
+  Matrix matrixBefore, matrixAfter;
+  freeLookCameraActor.GetProperty( CameraActor::CameraActor::Property::VIEW_MATRIX ).Get( matrixBefore );
+  freeLookCameraActor.SetProperty( Dali::DevelCameraActor::Property::REFLECTION_PLANE, Vector4( 0.0f, 1.0f, 0.0f, 0.0f));
+  stage.GetRootLayer().SetPosition( 0, 0 );
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+
+  freeLookCameraActor.GetProperty( CameraActor::CameraActor::Property::VIEW_MATRIX ).Get( matrixAfter );
+
+  Vector3 position, scale;
+  Quaternion rotation;
+  matrixAfter.GetTransformComponents( position, rotation, scale );
+
+  Quaternion reflected( 0, 0, 1, 0 );
+
+  DALI_TEST_EQUALS( reflected, rotation, 0.01f, TEST_LOCATION );
+
+  // Test Free Look camera
+  freeLookCameraActor.SetType(Camera::FREE_LOOK);
+
+  // Make sure the recalculation will take place
+  freeLookCameraActor.SetProperty( Dali::DevelCameraActor::Property::REFLECTION_PLANE, Vector4( 0.0f, 1.0f, 0.0f, 0.0f));
+
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+  application.Render();
+
+  // Nothing should change despite of different camera type
+  matrixAfter.GetTransformComponents( position, rotation, scale );
+  DALI_TEST_EQUALS( reflected, rotation, 0.01f, TEST_LOCATION );
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/dali/devel-api/actors/camera-actor-devel.h b/dali/devel-api/actors/camera-actor-devel.h
new file mode 100644 (file)
index 0000000..0f5d975
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef DALI_CAMERA_ACTOR_DEVEL_H
+#define DALI_CAMERA_ACTOR_DEVEL_H
+
+/*
+ * Copyright (c) 2020 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/actors/actor.h>
+
+namespace Dali
+{
+namespace DevelCameraActor
+{
+namespace Property
+{
+enum
+{
+  /**
+   * @brief Defines reflection plane for the camera
+   * @details Type Property::VECTOR4
+   * @note Optional
+   */
+  REFLECTION_PLANE = CameraActor::Property::INVERT_Y_AXIS + 1
+};
+
+} // Namespace Property
+} // Namesapce DevelCameraActor
+} // Namespace Dali
+
+#endif // DALI_CAMERA_ACTOR_DEVEL_H
index 5ac372f..1680c9b 100644 (file)
@@ -39,6 +39,7 @@ SET( devel_api_core_actors_header_files
   ${devel_api_src_dir}/actors/actor-devel.h
   ${devel_api_src_dir}/actors/custom-actor-devel.h
   ${devel_api_src_dir}/actors/layer-devel.h
+  ${devel_api_src_dir}/actors/camera-actor-devel.h
 )
 
 
index b531ab6..86e8e80 100644 (file)
@@ -25,6 +25,7 @@
 // INTERNAL INCLUDES
 #include <dali/public-api/common/stage.h>
 #include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/actors/camera-actor-devel.h>
 #include <dali/integration-api/debug.h>
 #include <dali/internal/event/common/property-helper.h>
 #include <dali/internal/event/common/stage-impl.h>
@@ -208,6 +209,14 @@ void CameraActor::OnStageConnectionInternal()
   }
 }
 
+void CameraActor::SetReflectByPlane(const Vector4& plane) {
+  SceneGraph::Camera* cam = const_cast<SceneGraph::Camera*>(GetCamera());
+  if (cam)
+  {
+    cam->SetReflectByPlane(plane);
+  }
+}
+
 void CameraActor::SetTarget( const Vector3& target )
 {
   if( target != mTarget ) // using range epsilon
@@ -618,6 +627,12 @@ void CameraActor::SetDefaultProperty( Property::Index index, const Property::Val
         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;
+      }
+
       default:
       {
         DALI_LOG_WARNING( "Unknown property (%d)\n", index );
index ecc3638..e320d76 100644 (file)
@@ -53,6 +53,15 @@ public:
   static CameraActorPtr New( const Size& size );
 
   /**
+   * Sets the reflection plane for the camera
+   *
+   * @param[in] plane Plane parameters
+   *
+   * @note plane.xyz are normal vector of the plane.
+   */
+  void SetReflectByPlane( const Vector4& plane );
+
+  /**
    * @copydoc Dali::CameraActor::SetTargetPosition
    */
   void SetTarget( const Vector3& targetPosition );
index 0061b87..01bba05 100644 (file)
@@ -390,7 +390,9 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList,
                                                  const Matrix& projectionMatrix,
                                                  Integration::DepthBufferAvailable depthBufferAvailable,
                                                  Integration::StencilBufferAvailable stencilBufferAvailable,
-                                                 Vector<GLuint>& boundTextures )
+                                                 Vector<GLuint>& boundTextures,
+                                                 const RenderInstruction& instruction
+                                                 )
 {
   DALI_PRINT_RENDER_LIST( renderList );
 
@@ -448,7 +450,7 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList,
 
       // Render the item.
       item.mRenderer->Render( context, bufferIndex, *item.mNode, item.mModelMatrix, item.mModelViewMatrix,
-                              viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque, boundTextures );
+                              viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque, boundTextures, instruction ); // Added instruction for reflection effect
     }
   }
 }
@@ -493,7 +495,9 @@ void RenderAlgorithms::ProcessRenderInstruction( const RenderInstruction& instru
                            *projectionMatrix,
                             depthBufferAvailable,
                             stencilBufferAvailable,
-                            boundTextures );
+                            boundTextures,
+                            instruction //added for reflection effect
+                            );
       }
     }
   }
index 30c8041..26f4343 100644 (file)
@@ -124,7 +124,9 @@ class RenderAlgorithms
                                    const Matrix& projectionMatrix,
                                    Integration::DepthBufferAvailable depthBufferAvailable,
                                    Integration::StencilBufferAvailable stencilBufferAvailable,
-                                   Vector<GLuint>& boundTextures );
+                                   Vector<GLuint>& boundTextures,
+                                   const Dali::Internal::SceneGraph::RenderInstruction& instruction // in the case of reflection, things like CullFace need to be adjusted for reflection world   
+                                   );
 
     // Prevent copying:
     RenderAlgorithms( RenderAlgorithms& rhs );
index 3157f85..8605288 100644 (file)
@@ -123,6 +123,11 @@ public:
     // inlined as this is called once per frame per render instruction
     return &mCamera->GetProjectionMatrix( index );
   }
+  // for reflection effect
+  const Camera* GetCamera() const
+  {
+    return mCamera;
+  }
 
 private:
 
index e3f1684..eea391a 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/internal/render/shaders/scene-graph-shader.h>
 #include <dali/internal/render/shaders/program.h>
 #include <dali/internal/render/data-providers/node-data-provider.h>
+#include <dali/internal/render/common/render-instruction.h>
 
 namespace Dali
 {
@@ -526,7 +527,8 @@ void Renderer::Render( Context& context,
                        const Matrix& projectionMatrix,
                        const Vector3& size,
                        bool blend,
-                       Vector<GLuint>& boundTextures )
+                       Vector<GLuint>& boundTextures,
+                       const Dali::Internal::SceneGraph::RenderInstruction& instruction )
 {
   // Get the program to use:
   Program* program = mRenderDataProvider->GetShader().GetProgram();
@@ -537,7 +539,33 @@ void Renderer::Render( Context& context,
   }
 
   //Set cull face  mode
-  context.CullFace( mFaceCullingMode );
+  const Dali::Internal::SceneGraph::Camera* cam = instruction.GetCamera();
+  if (cam->GetReflectionUsed())
+  {
+    auto adjFaceCullingMode = mFaceCullingMode;
+    switch( mFaceCullingMode )
+    {
+      case FaceCullingMode::Type::FRONT:
+      {
+        adjFaceCullingMode = FaceCullingMode::Type::BACK;
+        break;
+      }
+      case FaceCullingMode::Type::BACK:
+      {
+        adjFaceCullingMode = FaceCullingMode::Type::FRONT;
+        break;
+      }
+      default:
+      {
+        // nothing to do, leave culling as it is
+      }
+    }
+    context.CullFace( adjFaceCullingMode );
+  }
+  else
+  {
+    context.CullFace( mFaceCullingMode );
+  }
 
   //Set blending mode
   SetBlending( context, blend );
index 406dff4..a544883 100755 (executable)
@@ -46,6 +46,8 @@ namespace SceneGraph
 class SceneController;
 class Shader;
 class NodeDataProvider;
+
+class RenderInstruction; //for relfection effect
 }
 
 namespace Render
@@ -351,6 +353,8 @@ public:
    * @param[in] size Size of the render item
    * @param[in] blend If true, blending is enabled
    * @param[in] boundTextures The textures bound for rendering
+   * @param[in] instruction. for use case like reflection where CullFace needs to be adjusted
+
    */
   void Render( Context& context,
                BufferIndex bufferIndex,
@@ -361,7 +365,9 @@ public:
                const Matrix& projectionMatrix,
                const Vector3& size,
                bool blend,
-               Vector<GLuint>& boundTextures );
+               Vector<GLuint>& boundTextures,
+               const Dali::Internal::SceneGraph::RenderInstruction& instruction //for reflection effect
+               );
 
   /**
    * Write the renderer's sort attributes to the passed in reference
index f6ecce5..71a2d52 100644 (file)
@@ -31,6 +31,10 @@ namespace // unnamed namespace
 {
 const uint32_t UPDATE_COUNT        = 2u;  // Update projection or view matrix this many frames after a change
 const uint32_t COPY_PREVIOUS_MATRIX = 1u; // Copy view or projection matrix from previous frame
+
+//For reflection and clipping plane
+const float REFLECTION_NORMALIZED_DEVICE_COORDINATE_PARAMETER_A = 2.0f;
+const float REFLECTION_NORMALIZED_DEVICE_COORDINATE_PARAMETER_D = 1.0f;
 }
 
 namespace Dali
@@ -261,6 +265,69 @@ void Camera::SetTargetPosition( const Vector3& targetPosition )
   mUpdateViewFlag = UPDATE_COUNT;
 }
 
+
+
+void VectorReflectedByPlane(Vector4 &out, Vector4 &in, Vector4 &plane)
+{
+  float d = float(2.0) * plane.Dot(in);
+  out.x = static_cast<float>(in.x - plane.x*d);
+  out.y = static_cast<float>(in.y - plane.y*d);
+  out.z = static_cast<float>(in.z - plane.z*d);
+  out.w = static_cast<float>(in.w - plane.w*d);
+}
+
+void Camera::AdjustNearPlaneForPerspective( Matrix& perspective, const Vector4& clipPlane )
+{
+  Vector4    q;
+  float* v = perspective.AsFloat();
+
+  q.x = (Sign(clipPlane.x) + v[8]) / v[0];
+  q.y = (Sign(clipPlane.y) + v[9]) / v[5];
+  q.z = -1.0f;
+  q.w = (1.0f + v[10]) / v[14];
+
+  // Calculate the scaled plane vector
+  Vector4 c = clipPlane * (REFLECTION_NORMALIZED_DEVICE_COORDINATE_PARAMETER_A / q.Dot( clipPlane));
+
+  // Replace the third row of the projection v
+  v[2] = c.x;
+  v[6] = c.y;
+  v[10] = c.z + REFLECTION_NORMALIZED_DEVICE_COORDINATE_PARAMETER_D;
+  v[14] = c.w;
+}
+
+void Camera::SetReflectByPlane( const Vector4& plane )
+{
+  float* v = mReflectionMtx.AsFloat();
+  float _2ab = -2.0f * plane.x * plane.y;
+  float _2ac = -2.0f * plane.x * plane.z;
+  float _2bc = -2.0f * plane.y * plane.z;
+
+  v[0] = 1.0f - 2.0f * plane.x * plane.x;
+  v[1] = _2ab;
+  v[2] = _2ac;
+  v[3] = 0.0f;
+
+  v[4] = _2ab;
+  v[5] = 1.0f - 2.0f * plane.y * plane.y;
+  v[6] = _2bc;
+  v[7] = 0.0f;
+
+  v[8] = _2ac;
+  v[9] = _2bc;
+  v[10] = 1.0f - 2.0f * plane.z * plane.z;
+  v[11] = 0.0f;
+
+  v[12] =    - 2 * plane.x * plane.w;
+  v[13] =    - 2 * plane.y * plane.w;
+  v[14] =    - 2 * plane.z * plane.w;
+  v[15] = 1.0f;
+
+  mUseReflection = true;
+  mReflectionPlane = plane;
+  mUpdateViewFlag = UPDATE_COUNT;
+}
+
 const Matrix& Camera::GetProjectionMatrix( BufferIndex bufferIndex ) const
 {
   return mProjectionMatrix[ bufferIndex ];
@@ -349,11 +416,27 @@ uint32_t Camera::UpdateViewMatrix( BufferIndex updateBufferIndex )
         {
           Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
           viewMatrix = mNode->GetWorldMatrix( updateBufferIndex );
+
+          if (mUseReflection)
+          {
+            const Matrix& owningNodeMatrix( mNode->GetWorldMatrix( updateBufferIndex ) );
+            Vector3 position{}, scale{};
+            Quaternion orientation{};
+            owningNodeMatrix.GetTransformComponents( position, orientation, scale );
+            mReflectionEye = position;
+            mUseReflectionClip = true;
+
+            Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
+            Matrix oldViewMatrix( viewMatrix );
+            Matrix::Multiply(viewMatrix, oldViewMatrix, mReflectionMtx);
+          }
+
           viewMatrix.Invert();
           mViewMatrix.SetDirty( updateBufferIndex );
           break;
         }
-          // camera orientation constrained to look at a target
+
+        // camera orientation constrained to look at a target
         case Dali::Camera::LOOK_AT_TARGET:
         {
           const Matrix& owningNodeMatrix( mNode->GetWorldMatrix( updateBufferIndex ) );
@@ -361,7 +444,42 @@ uint32_t Camera::UpdateViewMatrix( BufferIndex updateBufferIndex )
           Quaternion orientation;
           owningNodeMatrix.GetTransformComponents( position, orientation, scale );
           Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
-          LookAt( viewMatrix, position, mTargetPosition, orientation.Rotate( Vector3::YAXIS ) );
+
+          if (mUseReflection)
+          {
+            Vector3 up = orientation.Rotate( Vector3::YAXIS );
+            Vector4 position4 = Vector4(position);
+            Vector4 target4 = Vector4(mTargetPosition);
+            Vector4 up4 = Vector4(up);
+            Vector4 positionNew;
+            Vector4 targetNew;
+            Vector4 upNew;
+            Vector3 positionNew3;
+            Vector3 targetNewVector3;
+            Vector3 upNew3;
+
+            // eye
+            VectorReflectedByPlane(positionNew, position4, mReflectionPlane);
+            VectorReflectedByPlane(targetNew, target4, mReflectionPlane);
+            VectorReflectedByPlane(upNew, up4, mReflectionPlane);
+
+            positionNew3     = Vector3(positionNew);
+            targetNewVector3 = Vector3(targetNew);
+            upNew3           = Vector3(upNew);
+            LookAt(viewMatrix, positionNew3, targetNewVector3, upNew3 );
+
+            Matrix oldViewMatrix( viewMatrix );
+            Matrix tmp;
+            tmp.SetIdentityAndScale(Vector3(-1.0, 1.0,1.0));
+            Matrix::Multiply(viewMatrix, oldViewMatrix, tmp);
+
+            mReflectionEye = positionNew;
+            mUseReflectionClip = true;
+          }
+          else
+          {
+            LookAt( viewMatrix, position, mTargetPosition, orientation.Rotate( Vector3::YAXIS ) );
+          }
           mViewMatrix.SetDirty( updateBufferIndex );
           break;
         }
@@ -493,6 +611,32 @@ uint32_t Camera::UpdateProjection( BufferIndex updateBufferIndex )
                        mNearClippingPlane,
                        mFarClippingPlane,
                        mInvertYAxis );
+
+          //need to apply custom clipping plane
+          if (mUseReflectionClip)
+          {
+            Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
+            Matrix viewInv = viewMatrix;
+            viewInv.Invert();
+            viewInv.Transpose();
+
+            Dali::Vector4 adjReflectPlane = mReflectionPlane;
+            float d = mReflectionPlane.Dot(mReflectionEye);
+            if (d < 0)
+            {
+              adjReflectPlane.w = -adjReflectPlane.w;
+            }
+
+            Vector4 customClipping = viewInv * adjReflectPlane;
+            AdjustNearPlaneForPerspective(projectionMatrix, customClipping);
+
+            // Invert Z
+            Matrix matZ;
+            matZ.SetIdentity();
+            float* vZ = matZ.AsFloat();
+            vZ[10] = -vZ[10];
+            Matrix::Multiply(projectionMatrix, projectionMatrix , matZ);
+          }
           break;
         }
         case Dali::Camera::ORTHOGRAPHIC_PROJECTION:
index d17120f..a3bc173 100644 (file)
@@ -160,6 +160,21 @@ public:
   void SetTargetPosition( const Vector3& targetPosition );
 
   /**
+   * Sets the reflection plane
+   * @param[in] plane reflection plane
+   */
+  void SetReflectByPlane( const Vector4& plane );
+
+  /**
+   * Tests whether reflection is used
+   * @return True if used, False otherwise
+   */
+  bool GetReflectionUsed() const
+  {
+    return mUseReflection;
+  }
+
+  /**
    * Retrieve the view-matrix; this is double buffered for input handling.
    * @param[in] bufferIndex The buffer to read from.
    * @return The view-matrix.
@@ -265,6 +280,13 @@ private:
    */
   void UpdateFrustum( BufferIndex updateBufferIndex, bool normalize = true );
 
+  /**
+   * Adjust near plane for reflection
+   * @param perspective Perspective matrix
+   * @param clipPlane Clipping plane
+   */
+  void AdjustNearPlaneForPerspective( Matrix& perspective, const Vector4& clipPlane );
+
   uint32_t                  mUpdateViewFlag;       ///< This is non-zero if the view matrix requires an update
   uint32_t                  mUpdateProjectionFlag; ///< This is non-zero if the projection matrix requires an update
   const Node*                   mNode;                 ///< The node this scene graph camera belongs to
@@ -284,6 +306,12 @@ public:  // PROPERTIES
   float                         mFarClippingPlane;
   Vector3                       mTargetPosition;
 
+  Dali::Matrix                  mReflectionMtx;
+  Dali::Vector4                 mReflectionPlane;
+  Dali::Vector4                 mReflectionEye;
+  bool                          mUseReflection{ false };
+  bool                          mUseReflectionClip{ false };
+
   InheritedMatrix mViewMatrix;           ///< The viewMatrix; this is double buffered for input handling.
   InheritedMatrix mProjectionMatrix;     ///< The projectionMatrix; this is double buffered for input handling.