2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://floralicense.org/license/
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 #include <dali/internal/update/node-attachments/scene-graph-camera-attachment.h>
21 #include <dali/public-api/common/dali-common.h>
22 #include <dali/internal/update/nodes/node.h>
23 #include <dali/internal/update/controllers/scene-controller.h>
24 #include <dali/internal/update/resources/resource-manager.h>
25 #include <dali/integration-api/debug.h>
29 namespace // unnamed namespace
31 static unsigned int UPDATE_COUNT = 2u; // Update projection or view matrix this many frames after a change
32 static unsigned int COPY_PREVIOUS_PROJECTION = 1u; // Copy projection matrix from previous frame
47 void LookAt(Matrix& result, const Vector3& eye, const Vector3& target, const Vector3& up)
49 Vector3 vZ = target - eye;
52 Vector3 vX = up.Cross(vZ);
55 Vector3 vY = vZ.Cross(vX);
58 result.SetInverseTransformComponents(vX, vY, vZ, eye);
62 void Frustum(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis)
64 float deltaZ = far - near;
65 if ((near <= 0.0f) || (far <= 0.0f) || Equals(right, left) || Equals(bottom, top) || (deltaZ <= 0.0f))
67 DALI_LOG_ERROR("Invalid parameters passed into Frustum!");
68 DALI_ASSERT_DEBUG("Invalid parameters passed into Frustum!");
72 float deltaX = right - left;
73 float deltaY = invertYAxis ? bottom - top : top - bottom;
77 float* m = result.AsFloat();
78 m[0] = -2.0f * near / deltaX;
79 m[1] = m[2] = m[3] = 0.0f;
81 m[5] = -2.0f * near / deltaY;
82 m[4] = m[6] = m[7] = 0.0f;
84 m[8] = (right + left) / deltaX;
85 m[9] = (top + bottom) / deltaY;
86 m[10] = (near + far) / deltaZ;
89 m[14] = -2.0f * near * far / deltaZ;
90 m[12] = m[13] = m[15] = 0.0f;
93 void Perspective(Matrix& result, float fovy, float aspect, float near, float far, bool invertYAxis, float stereoBias )
95 float frustumH = tanf( fovy * 0.5f ) * near;
96 float frustumW = frustumH * aspect;
97 float bias = stereoBias * 0.5f;
99 Frustum(result, -(frustumW + bias), frustumW - bias, -frustumH, frustumH, near, far, invertYAxis);
102 void Orthographic(Matrix& result, float left, float right, float bottom, float top, float near, float far, bool invertYAxis)
104 if ( Equals(right, left) || Equals(top, bottom) || Equals(far, near) )
106 DALI_LOG_ERROR( "Cannot create orthographic projection matrix with a zero dimension." );
107 DALI_ASSERT_DEBUG( "Cannot create orthographic projection matrix with a zero dimension." );
111 float deltaX = right - left;
112 float deltaY = invertYAxis ? bottom - top : top - bottom;
113 float deltaZ = far - near;
115 float *m = result.AsFloat();
116 m[0] = -2.0f / deltaX;
122 m[5] = -2.0f / deltaY;
128 m[10] = 2.0f / deltaZ;
130 m[12] = -(right + left) / deltaX;
131 m[13] = -(top + bottom) / deltaY;
132 m[14] = -(near + far) / deltaZ;
136 } // unnamed namespace
138 const Dali::Camera::Type CameraAttachment::DEFAULT_TYPE( Dali::Camera::LOOK_AT_TARGET );
139 const Dali::Camera::ProjectionMode CameraAttachment::DEFAULT_MODE( Dali::Camera::PERSPECTIVE_PROJECTION );
140 const bool CameraAttachment::DEFAULT_INVERT_Y_AXIS( false );
141 const float CameraAttachment::DEFAULT_FIELD_OF_VIEW( 45.0f*(M_PI/180.0f) );
142 const float CameraAttachment::DEFAULT_ASPECT_RATIO( 4.0f/3.0f );
143 const float CameraAttachment::DEFAULT_STEREO_BIAS( 0.0f );
144 const float CameraAttachment::DEFAULT_LEFT_CLIPPING_PLANE(-240.0f);
145 const float CameraAttachment::DEFAULT_RIGHT_CLIPPING_PLANE(240.0f);
146 const float CameraAttachment::DEFAULT_TOP_CLIPPING_PLANE(-400.0f);
147 const float CameraAttachment::DEFAULT_BOTTOM_CLIPPING_PLANE(400.0f);
148 const float CameraAttachment::DEFAULT_NEAR_CLIPPING_PLANE( 800.0f ); // default height of the screen
149 const float CameraAttachment::DEFAULT_FAR_CLIPPING_PLANE( DEFAULT_NEAR_CLIPPING_PLANE + 2.f * DEFAULT_NEAR_CLIPPING_PLANE );
150 const Vector3 CameraAttachment::DEFAULT_TARGET_POSITION( 0.0f, 0.0f, 0.0f );
153 CameraAttachment::CameraAttachment()
155 mUpdateViewFlag( UPDATE_COUNT ),
156 mUpdateProjectionFlag( UPDATE_COUNT ),
157 mType( DEFAULT_TYPE ),
158 mProjectionMode( DEFAULT_MODE ),
159 mInvertYAxis( DEFAULT_INVERT_Y_AXIS ),
160 mFieldOfView( DEFAULT_FIELD_OF_VIEW ),
161 mAspectRatio( DEFAULT_ASPECT_RATIO ),
162 mStereoBias( DEFAULT_STEREO_BIAS ),
163 mLeftClippingPlane( DEFAULT_LEFT_CLIPPING_PLANE ),
164 mRightClippingPlane( DEFAULT_RIGHT_CLIPPING_PLANE ),
165 mTopClippingPlane( DEFAULT_TOP_CLIPPING_PLANE ),
166 mBottomClippingPlane( DEFAULT_BOTTOM_CLIPPING_PLANE ),
167 mNearClippingPlane( DEFAULT_NEAR_CLIPPING_PLANE ),
168 mFarClippingPlane( DEFAULT_FAR_CLIPPING_PLANE ),
169 mTargetPosition( DEFAULT_TARGET_POSITION ),
170 mViewMatrix( Matrix::IDENTITY ),
171 mProjectionMatrix( Matrix::IDENTITY ),
172 mInverseViewProjection( Matrix::IDENTITY )
176 CameraAttachment* CameraAttachment::New()
178 return new CameraAttachment();
181 void CameraAttachment::ConnectToSceneGraph( SceneController& sceneController, BufferIndex updateBufferIndex )
186 void CameraAttachment::OnDestroy()
191 CameraAttachment::~CameraAttachment()
195 RenderableAttachment* CameraAttachment::GetRenderable()
200 void CameraAttachment::SetType( Dali::Camera::Type type )
205 void CameraAttachment::SetProjectionMode( Dali::Camera::ProjectionMode mode )
207 mProjectionMode = mode;
208 mUpdateProjectionFlag = UPDATE_COUNT;
211 void CameraAttachment::SetInvertYAxis( bool invertYAxis )
213 mInvertYAxis = invertYAxis;
214 mUpdateProjectionFlag = UPDATE_COUNT;
217 void CameraAttachment::SetFieldOfView( float fieldOfView )
219 mFieldOfView = fieldOfView;
220 mUpdateProjectionFlag = UPDATE_COUNT;
223 void CameraAttachment::SetAspectRatio( float aspectRatio )
225 mAspectRatio = aspectRatio;
226 mUpdateProjectionFlag = UPDATE_COUNT;
229 void CameraAttachment::SetStereoBias( float stereoBias )
231 mStereoBias = stereoBias;
232 mUpdateProjectionFlag = UPDATE_COUNT;
235 void CameraAttachment::SetLeftClippingPlane( float leftClippingPlane )
237 mLeftClippingPlane = leftClippingPlane;
238 mUpdateProjectionFlag = UPDATE_COUNT;
241 void CameraAttachment::SetRightClippingPlane( float rightClippingPlane )
243 mRightClippingPlane = rightClippingPlane;
244 mUpdateProjectionFlag = UPDATE_COUNT;
247 void CameraAttachment::SetTopClippingPlane( float topClippingPlane )
249 mTopClippingPlane = topClippingPlane;
250 mUpdateProjectionFlag = UPDATE_COUNT;
253 void CameraAttachment::SetBottomClippingPlane( float bottomClippingPlane )
255 mBottomClippingPlane = bottomClippingPlane;
256 mUpdateProjectionFlag = UPDATE_COUNT;
259 void CameraAttachment::SetNearClippingPlane( float nearClippingPlane )
261 mNearClippingPlane = nearClippingPlane;
262 mUpdateProjectionFlag = UPDATE_COUNT;
265 void CameraAttachment::SetFarClippingPlane( float farClippingPlane )
267 mFarClippingPlane = farClippingPlane;
268 mUpdateProjectionFlag = UPDATE_COUNT;
271 void CameraAttachment::SetTargetPosition( const Vector3& targetPosition )
273 mTargetPosition = targetPosition;
274 mUpdateViewFlag = UPDATE_COUNT;
277 const Matrix& CameraAttachment::GetProjectionMatrix( BufferIndex bufferIndex ) const
279 return mProjectionMatrix[ bufferIndex ];
282 const Matrix& CameraAttachment::GetViewMatrix( BufferIndex bufferIndex ) const
284 return mViewMatrix[ bufferIndex ];
287 const Matrix& CameraAttachment::GetInverseViewProjectionMatrix( BufferIndex bufferIndex ) const
289 return mInverseViewProjection[ bufferIndex ];
292 const PropertyInputImpl* CameraAttachment::GetProjectionMatrix() const
294 return &mProjectionMatrix;
297 const PropertyInputImpl* CameraAttachment::GetViewMatrix() const
302 void CameraAttachment::Update( BufferIndex updateBufferIndex, const Node& owningNode, int nodeDirtyFlags )
304 // if owning node has changes in world position we need to update camera for next 2 frames
305 if( nodeDirtyFlags & TransformFlag )
307 mUpdateViewFlag = UPDATE_COUNT;
309 if( nodeDirtyFlags & VisibleFlag )
311 // If the visibility changes, the projection matrix needs to be re-calculated.
312 // It may happen the first time an actor is rendered it's rendered only once and becomes invisible,
313 // in the following update the node will be skipped leaving the projection matrix (double buffered)
314 // with the Identity.
315 mUpdateProjectionFlag = UPDATE_COUNT;
317 if( 0u != mUpdateViewFlag )
322 // camera orientation taken from node - i.e. look in abitrary, unconstrained direction
323 case Dali::Camera::FREE_LOOK:
325 Matrix& viewMatrix = mViewMatrix.Get(updateBufferIndex);
326 viewMatrix.SetInverseTransformComponents(
328 owningNode.GetWorldRotation(updateBufferIndex),
329 owningNode.GetWorldPosition(updateBufferIndex) );
331 mViewMatrix.SetDirty(updateBufferIndex);
335 // camera orientation constrained to look at a target
336 case Dali::Camera::LOOK_AT_TARGET:
338 Matrix& viewMatrix = mViewMatrix.Get(updateBufferIndex);
340 owningNode.GetWorldPosition(updateBufferIndex),
342 owningNode.GetWorldRotation(updateBufferIndex).Rotate(Vector3::YAXIS) );
344 mViewMatrix.SetDirty(updateBufferIndex);
350 UpdateProjection( updateBufferIndex );
353 bool CameraAttachment::ViewMatrixUpdated()
355 return 0u != mUpdateViewFlag;
358 void CameraAttachment::UpdateProjection( BufferIndex updateBufferIndex )
360 // Early-exit if no update required
361 if ( 0u != mUpdateProjectionFlag )
363 if ( COPY_PREVIOUS_PROJECTION == mUpdateProjectionFlag )
365 // The projection matrix was updated in the previous frame; copy it
366 mProjectionMatrix.CopyPrevious( updateBufferIndex );
368 else // UPDATE_COUNT == mUpdateProjectionFlag
370 switch( mProjectionMode )
372 case Dali::Camera::PERSPECTIVE_PROJECTION:
374 Matrix &projectionMatrix = mProjectionMatrix.Get(updateBufferIndex);
375 Perspective( projectionMatrix,
384 case Dali::Camera::ORTHOGRAPHIC_PROJECTION:
386 Matrix &projectionMatrix = mProjectionMatrix.Get(updateBufferIndex);
387 Orthographic( projectionMatrix,
388 mLeftClippingPlane, mRightClippingPlane,
389 mBottomClippingPlane, mTopClippingPlane,
390 mNearClippingPlane, mFarClippingPlane,
396 mProjectionMatrix.SetDirty(updateBufferIndex);
398 --mUpdateProjectionFlag;
401 // if model or view matrix changed we need to recalculate the inverse VP
402 if( !mViewMatrix.IsClean() || !mProjectionMatrix.IsClean() )
404 UpdateInverseViewProjection( updateBufferIndex );
408 void CameraAttachment::UpdateInverseViewProjection( BufferIndex updateBufferIndex )
410 Matrix::Multiply( mInverseViewProjection[ updateBufferIndex ], mViewMatrix[ updateBufferIndex ], mProjectionMatrix[ updateBufferIndex ] );
411 // ignore the error, if the view projection is incorrect (non inversible) then you will have tough times anyways
412 static_cast< void >( mInverseViewProjection[ updateBufferIndex ].Invert() );
415 } // namespace SceneGraph
417 } // namespace Internal