From: Adeel Kazmi Date: Fri, 20 Mar 2020 18:21:39 +0000 (+0000) Subject: Merge "Implementation of reflection feature" into devel/master X-Git-Tag: dali_1.9.5~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f022a30b115efa5dbab07e21655332b59d0260ca;hp=fc625ceac8c1451db1e6b6ef00bc808a3b92c28a;p=platform%2Fcore%2Fuifw%2Fdali-core.git Merge "Implementation of reflection feature" into devel/master --- diff --git a/automated-tests/src/dali/utc-Dali-CameraActor.cpp b/automated-tests/src/dali/utc-Dali-CameraActor.cpp index de0cb29..85d6465 100644 --- a/automated-tests/src/dali/utc-Dali-CameraActor.cpp +++ b/automated-tests/src/dali/utc-Dali-CameraActor.cpp @@ -21,7 +21,7 @@ #include #include #include - +#include #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 index 0000000..0f5d975 --- /dev/null +++ b/dali/devel-api/actors/camera-actor-devel.h @@ -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 + +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 diff --git a/dali/devel-api/file.list b/dali/devel-api/file.list index 5ac372f..1680c9b 100644 --- a/dali/devel-api/file.list +++ b/dali/devel-api/file.list @@ -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 ) diff --git a/dali/internal/event/actors/camera-actor-impl.cpp b/dali/internal/event/actors/camera-actor-impl.cpp index b531ab6..86e8e80 100644 --- a/dali/internal/event/actors/camera-actor-impl.cpp +++ b/dali/internal/event/actors/camera-actor-impl.cpp @@ -25,6 +25,7 @@ // INTERNAL INCLUDES #include #include +#include #include #include #include @@ -208,6 +209,14 @@ void CameraActor::OnStageConnectionInternal() } } +void CameraActor::SetReflectByPlane(const Vector4& plane) { + SceneGraph::Camera* cam = const_cast(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() ); // set to false in case property is not bool break; } + case Dali::DevelCameraActor::Property::REFLECTION_PLANE: + { + SetReflectByPlane( propertyValue.Get() ); + break; + } + default: { DALI_LOG_WARNING( "Unknown property (%d)\n", index ); diff --git a/dali/internal/event/actors/camera-actor-impl.h b/dali/internal/event/actors/camera-actor-impl.h index ecc3638..e320d76 100644 --- a/dali/internal/event/actors/camera-actor-impl.h +++ b/dali/internal/event/actors/camera-actor-impl.h @@ -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 ); diff --git a/dali/internal/render/common/render-algorithms.cpp b/dali/internal/render/common/render-algorithms.cpp index 0061b87..01bba05 100644 --- a/dali/internal/render/common/render-algorithms.cpp +++ b/dali/internal/render/common/render-algorithms.cpp @@ -390,7 +390,9 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList, const Matrix& projectionMatrix, Integration::DepthBufferAvailable depthBufferAvailable, Integration::StencilBufferAvailable stencilBufferAvailable, - Vector& boundTextures ) + Vector& 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 + ); } } } diff --git a/dali/internal/render/common/render-algorithms.h b/dali/internal/render/common/render-algorithms.h index 30c8041..26f4343 100644 --- a/dali/internal/render/common/render-algorithms.h +++ b/dali/internal/render/common/render-algorithms.h @@ -124,7 +124,9 @@ class RenderAlgorithms const Matrix& projectionMatrix, Integration::DepthBufferAvailable depthBufferAvailable, Integration::StencilBufferAvailable stencilBufferAvailable, - Vector& boundTextures ); + Vector& 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 ); diff --git a/dali/internal/render/common/render-instruction.h b/dali/internal/render/common/render-instruction.h index 3157f85..8605288 100644 --- a/dali/internal/render/common/render-instruction.h +++ b/dali/internal/render/common/render-instruction.h @@ -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: diff --git a/dali/internal/render/renderers/render-renderer.cpp b/dali/internal/render/renderers/render-renderer.cpp index e3f1684..eea391a 100644 --- a/dali/internal/render/renderers/render-renderer.cpp +++ b/dali/internal/render/renderers/render-renderer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace Dali { @@ -526,7 +527,8 @@ void Renderer::Render( Context& context, const Matrix& projectionMatrix, const Vector3& size, bool blend, - Vector& boundTextures ) + Vector& 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 ); diff --git a/dali/internal/render/renderers/render-renderer.h b/dali/internal/render/renderers/render-renderer.h index 406dff4..a544883 100755 --- a/dali/internal/render/renderers/render-renderer.h +++ b/dali/internal/render/renderers/render-renderer.h @@ -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& boundTextures ); + Vector& boundTextures, + const Dali::Internal::SceneGraph::RenderInstruction& instruction //for reflection effect + ); /** * Write the renderer's sort attributes to the passed in reference diff --git a/dali/internal/update/render-tasks/scene-graph-camera.cpp b/dali/internal/update/render-tasks/scene-graph-camera.cpp index f6ecce5..71a2d52 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.cpp +++ b/dali/internal/update/render-tasks/scene-graph-camera.cpp @@ -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(in.x - plane.x*d); + out.y = static_cast(in.y - plane.y*d); + out.z = static_cast(in.z - plane.z*d); + out.w = static_cast(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: diff --git a/dali/internal/update/render-tasks/scene-graph-camera.h b/dali/internal/update/render-tasks/scene-graph-camera.h index d17120f..a3bc173 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.h +++ b/dali/internal/update/render-tasks/scene-graph-camera.h @@ -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.