utc-Dali-Internal-FixedSizeMemoryPool.cpp
utc-Dali-Internal-MemoryPoolObjectAllocator.cpp
utc-Dali-Internal-RelayoutController.cpp
+ utc-Dali-Internal-FrustumCulling.cpp
)
LIST(APPEND TC_SOURCES
--- /dev/null
+/*
+ * Copyright (c) 2014 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 <iostream>
+#include <algorithm>
+#include <stdlib.h>
+#include <dali/public-api/dali-core.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+#define MAKE_SHADER(A)#A
+
+const char* VERTEX_SHADER = MAKE_SHADER(
+attribute mediump vec2 aPosition;
+attribute mediump vec2 aTexCoord;
+uniform mediump mat4 uMvpMatrix;
+uniform mediump vec3 uSize;
+varying mediump vec2 vTexCoord;
+
+void main()
+{
+ mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);
+ vertexPosition.xyz *= uSize;
+ vertexPosition = uMvpMatrix * vertexPosition;
+ vTexCoord = aTexCoord;
+ gl_Position = vertexPosition;
+}
+);
+
+const char* FRAGMENT_SHADER = MAKE_SHADER(
+uniform Sampler2D sTexture;
+varying mediump vec2 vTexCoord;
+void main()
+{
+ gl_FragColor = texture2D( sTexture, vTexCoord );
+}
+);
+
+Geometry CreateGeometry()
+{
+ const float halfQuadSize = .5f;
+ struct TexturedQuadVertex { Vector2 position; Vector2 textureCoordinates; };
+ TexturedQuadVertex texturedQuadVertexData[4] = {
+ { Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f) },
+ { Vector2( halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f) },
+ { Vector2(-halfQuadSize, halfQuadSize), Vector2(0.f, 1.f) },
+ { Vector2( halfQuadSize, halfQuadSize), Vector2(1.f, 1.f) } };
+
+ Property::Map texturedQuadVertexFormat;
+ texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
+ texturedQuadVertexFormat["aTexCoord"] = Property::VECTOR2;
+ PropertyBuffer texturedQuadVertices = PropertyBuffer::New( texturedQuadVertexFormat, 4 );
+ texturedQuadVertices.SetData(texturedQuadVertexData);
+
+ // Create indices
+ unsigned int indexData[6] = { 0, 3, 1, 0, 2, 3 };
+ Property::Map indexFormat;
+ indexFormat["indices"] = Property::UNSIGNED_INTEGER;
+ PropertyBuffer indices = PropertyBuffer::New( indexFormat, sizeof(indexData)/sizeof(indexData[0]) );
+ indices.SetData(indexData);
+
+ // Create the geometry object
+ Geometry texturedQuadGeometry = Geometry::New();
+ texturedQuadGeometry.AddVertexBuffer( texturedQuadVertices );
+ texturedQuadGeometry.SetIndexBuffer( indices );
+
+ return texturedQuadGeometry;
+}
+
+int UtcFrustumCullN(void)
+{
+ TestApplication application;
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ PixelBuffer* pixelBuffer = new PixelBuffer[ 4 ];
+ BufferImage image = BufferImage::New( pixelBuffer, 1, 1 );
+
+ Geometry geometry = CreateGeometry();
+ Material material = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ) );
+ Sampler sampler = Sampler::New( image, "sTexture" );
+ material.AddSampler( sampler );
+ Renderer renderer = Renderer::New( geometry, material );
+
+ Actor meshActor = Actor::New();
+ meshActor.AddRenderer( renderer );
+ meshActor.SetSize(400, 400);
+ drawTrace.Reset();
+
+ meshActor.SetParentOrigin( ParentOrigin::CENTER );
+ meshActor.SetAnchorPoint( AnchorPoint::CENTER );
+ Stage::GetCurrent().Add( meshActor );
+
+ application.SendNotification();
+ application.Render(16);
+ DALI_TEST_CHECK( drawTrace.FindMethod( "DrawElements" ) );
+ END_TEST;
+}
+
+int UtcFrustumLeftCullP(void)
+{
+ TestApplication application;
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ PixelBuffer* pixelBuffer = new PixelBuffer[ 4 ];
+ BufferImage image = BufferImage::New( pixelBuffer, 1, 1 );
+
+ Geometry geometry = CreateGeometry();
+ Material material = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ) );
+ Sampler sampler = Sampler::New( image, "sTexture" );
+ material.AddSampler( sampler );
+ Renderer renderer = Renderer::New( geometry, material );
+
+ Actor meshActor = Actor::New();
+ meshActor.AddRenderer( renderer );
+ meshActor.SetSize(400, 400);
+ drawTrace.Reset();
+
+ meshActor.SetParentOrigin( Vector3( -0.42f, 0.5f, 0.5f ) );
+ meshActor.SetAnchorPoint( AnchorPoint::CENTER );
+ Stage::GetCurrent().Add( meshActor );
+
+ application.SendNotification();
+ application.Render(16);
+
+ // This will be box culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+
+ drawTrace.Reset();
+ meshActor.SetParentOrigin( Vector3( -0.5f, 0.5f, 0.5f ) );
+ application.SendNotification();
+ application.Render(16);
+
+ // This will be sphere culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+ END_TEST;
+}
+
+int UtcFrustumRightCullP(void)
+{
+ TestApplication application;
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ PixelBuffer* pixelBuffer = new PixelBuffer[ 4 ];
+ BufferImage image = BufferImage::New( pixelBuffer, 1, 1 );
+
+ Geometry geometry = CreateGeometry();
+ Material material = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ) );
+ Sampler sampler = Sampler::New( image, "sTexture" );
+ material.AddSampler( sampler );
+ Renderer renderer = Renderer::New( geometry, material );
+
+ Actor meshActor = Actor::New();
+ meshActor.AddRenderer( renderer );
+ meshActor.SetSize(400, 400);
+ drawTrace.Reset();
+
+ meshActor.SetParentOrigin( Vector3( 1.42f, 0.5f, 0.5f ) );
+ meshActor.SetAnchorPoint( AnchorPoint::CENTER );
+ Stage::GetCurrent().Add( meshActor );
+
+ application.SendNotification();
+ application.Render(16);
+
+ // This should be box culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+
+ drawTrace.Reset();
+ meshActor.SetParentOrigin( Vector3( 1.5f, 0.0f, 0.5f ) );
+ application.SendNotification();
+ application.Render(16);
+
+ // This should be sphere culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+ END_TEST;
+}
+
+int UtcFrustumTopCullP(void)
+{
+ TestApplication application;
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ PixelBuffer* pixelBuffer = new PixelBuffer[ 4 ];
+ BufferImage image = BufferImage::New( pixelBuffer, 1, 1 );
+
+ Geometry geometry = CreateGeometry();
+ Material material = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ) );
+ Sampler sampler = Sampler::New( image, "sTexture" );
+ material.AddSampler( sampler );
+ Renderer renderer = Renderer::New( geometry, material );
+
+ Actor meshActor = Actor::New();
+ meshActor.AddRenderer( renderer );
+ meshActor.SetSize(400, 400);
+ drawTrace.Reset();
+
+ meshActor.SetParentOrigin( Vector3( 0.5f, -0.32f, 0.5f ) );
+ meshActor.SetAnchorPoint( AnchorPoint::CENTER );
+ Stage::GetCurrent().Add( meshActor );
+
+ application.SendNotification();
+ application.Render(16);
+
+ // This should be box culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+
+ drawTrace.Reset();
+ meshActor.SetParentOrigin( Vector3( 0.5f, -0.5f, 0.5f ) );
+ application.SendNotification();
+ application.Render(16);
+
+ // This will be sphere culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+ END_TEST;
+}
+
+int UtcFrustumBottomCullP(void)
+{
+ TestApplication application;
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ PixelBuffer* pixelBuffer = new PixelBuffer[ 4 ];
+ BufferImage image = BufferImage::New( pixelBuffer, 1, 1 );
+
+ Geometry geometry = CreateGeometry();
+ Material material = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ) );
+ Sampler sampler = Sampler::New( image, "sTexture" );
+ material.AddSampler( sampler );
+ Renderer renderer = Renderer::New( geometry, material );
+
+ Actor meshActor = Actor::New();
+ meshActor.AddRenderer( renderer );
+ meshActor.SetSize(400, 400);
+ drawTrace.Reset();
+
+ meshActor.SetParentOrigin( Vector3( 0.5f, 1.32f, 0.5f ) );
+ meshActor.SetAnchorPoint( AnchorPoint::CENTER );
+ Stage::GetCurrent().Add( meshActor );
+
+ application.SendNotification();
+ application.Render(16);
+
+ // This should be box culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+
+ drawTrace.Reset();
+ meshActor.SetParentOrigin( Vector3( 0.5f, 1.5f, 0.5f ) );
+ application.SendNotification();
+ application.Render(16);
+
+ // This will be sphere culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+ END_TEST;
+}
+
+int UtcFrustumNearCullP(void)
+{
+ TestApplication application;
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ PixelBuffer* pixelBuffer = new PixelBuffer[ 4 ];
+ BufferImage image = BufferImage::New( pixelBuffer, 1, 1 );
+
+ Geometry geometry = CreateGeometry();
+ Material material = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ) );
+ Sampler sampler = Sampler::New( image, "sTexture" );
+ material.AddSampler( sampler );
+ Renderer renderer = Renderer::New( geometry, material );
+
+ Actor meshActor = Actor::New();
+ meshActor.AddRenderer( renderer );
+ meshActor.SetSize(400, 400);
+ drawTrace.Reset();
+
+ meshActor.SetParentOrigin( Vector3( 0.5f, 0.5f, 7.0f ) );
+ meshActor.SetAnchorPoint( AnchorPoint::CENTER );
+ Stage::GetCurrent().Add( meshActor );
+
+ application.SendNotification();
+ application.Render(16);
+
+ // This will be sphere culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+ END_TEST;
+}
+
+int UtcFrustumFarCullP(void)
+{
+ TestApplication application;
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ PixelBuffer* pixelBuffer = new PixelBuffer[ 4 ];
+ BufferImage image = BufferImage::New( pixelBuffer, 1, 1 );
+
+ Geometry geometry = CreateGeometry();
+ Material material = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ) );
+ Sampler sampler = Sampler::New( image, "sTexture" );
+ material.AddSampler( sampler );
+ Renderer renderer = Renderer::New( geometry, material );
+
+ Actor meshActor = Actor::New();
+ meshActor.AddRenderer( renderer );
+ meshActor.SetSize(400, 400);
+ drawTrace.Reset();
+
+ meshActor.SetParentOrigin( Vector3( 0.5f, 0.5f, -7.0f ) );
+ meshActor.SetAnchorPoint( AnchorPoint::CENTER );
+ Stage::GetCurrent().Add( meshActor );
+
+ application.SendNotification();
+ application.Render(16);
+
+ // This will be sphere culled
+ DALI_TEST_CHECK( !drawTrace.FindMethod( "DrawElements" ) );
+ END_TEST;
+}
+
+int UtcFrustumCullDisabledP(void)
+{
+ TestApplication application;
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+ drawTrace.Enable(true);
+
+ PixelBuffer* pixelBuffer = new PixelBuffer[ 4 ];
+ BufferImage image = BufferImage::New( pixelBuffer, 1, 1 );
+
+ Geometry geometry = CreateGeometry();
+ Material material = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, Shader::HINT_MODIFIES_GEOMETRY ) );
+ Sampler sampler = Sampler::New( image, "sTexture" );
+ material.AddSampler( sampler );
+ Renderer renderer = Renderer::New( geometry, material );
+
+ Actor meshActor = Actor::New();
+ meshActor.AddRenderer( renderer );
+ meshActor.SetSize(400, 400);
+ drawTrace.Reset();
+
+ meshActor.SetParentOrigin( Vector3( 0.5f, 0.5f, -7.0f ) );
+ meshActor.SetAnchorPoint( AnchorPoint::CENTER );
+ Stage::GetCurrent().Add( meshActor );
+
+ application.SendNotification();
+ application.Render(16);
+
+ // This should not be culled
+ DALI_TEST_CHECK( drawTrace.FindMethod( "DrawElements" ) );
+ END_TEST;
+}
\ No newline at end of file
: mIndexBuffer( NULL ),
mCenter(),
mHalfExtents(),
+ mRadius( 0.0f ),
mGeometryType(Dali::Geometry::TRIANGLES),
mRequiresDepthTest(false)
{
void Geometry::AddVertexBuffer( PropertyBuffer* vertexBuffer )
{
mVertexBuffers.PushBack( vertexBuffer );
+ CalculateExtents( vertexBuffer );
vertexBuffer->AddUniformMapObserver(*this);
mConnectionObservers.ConnectionsChanged(*this);
}
// Reset the animated properties
mCenter.ResetToBaseValue( updateBufferIndex );
mHalfExtents.ResetToBaseValue( updateBufferIndex );
+ mRadius.ResetToBaseValue( updateBufferIndex );
// Age the double buffered properties
mGeometryType.CopyPrevious(updateBufferIndex);
mRequiresDepthTest.CopyPrevious(updateBufferIndex);
}
+void Geometry::CalculateExtents( PropertyBuffer* vertexBuffer )
+{
+ // TODO calculate extents for all vertex buffers attached to geometry
+ unsigned int elementIndex = 0;
+ unsigned int elementCount = vertexBuffer->GetElementCount( 0 );
+ unsigned int elementCount1 = vertexBuffer->GetElementCount( 1 );
+
+ // Select the double buffered element list that is the largest...
+ if ( elementCount < elementCount1 )
+ {
+ elementCount = elementCount1;
+ elementIndex = 1;
+ }
+
+ unsigned int attributeCount = vertexBuffer->GetAttributeCount( elementIndex );
+ unsigned int elementSize = vertexBuffer->GetElementSize( elementIndex );
+
+ std::string posName( "aPos" );
+ std::size_t found;
+
+ float left = 0.0f;
+ float right = 0.0f;
+ float top = 0.0f;
+ float bottom = 0.0f;
+
+ // Find the position attribute index
+ for ( unsigned int i = 0; i < attributeCount; ++i )
+ {
+ found = vertexBuffer->GetAttributeName( 0, i ).find( posName );
+ if ( found != std::string::npos )
+ {
+ unsigned int offset = vertexBuffer->GetAttributeOffset( elementIndex, i );
+ const PropertyBufferDataProvider::BufferType& data = vertexBuffer->GetData( elementIndex );
+
+ // Check attribute type to determine correct position type
+ Property::Type positionType = vertexBuffer->GetAttributeType( elementIndex, i );
+ Vector3 halfExtents;
+ Vector3 center;
+ switch ( positionType )
+ {
+ case Property::VECTOR2:
+ {
+ for ( unsigned int j = 0; j < elementCount; ++j )
+ {
+ const Vector2* position = reinterpret_cast< const Vector2* >( &data[ offset ] );
+ offset += elementSize;
+
+ if ( position->x < left )
+ {
+ left = position->x;
+ }
+ if ( position->x > right )
+ {
+ right = position->x;
+ }
+ if ( position->y < top )
+ {
+ top = position->y;
+ }
+ if ( position->y > bottom )
+ {
+ bottom = position->y;
+ }
+ }
+
+ halfExtents = Vector3( ( right - left ) * 0.5f, ( bottom - top ) * 0.5f, 0.0f );
+ center = Vector3( halfExtents.x + left , halfExtents.y + top, 0.0f );
+ break;
+ }
+ case Property::VECTOR3:
+ {
+ float near = 0.0f;
+ float far = 0.0f;
+ for ( unsigned int j = 0; j < elementCount; ++j )
+ {
+ const Vector3* position = reinterpret_cast< const Vector3* >( &data[ offset ] );
+ offset += elementSize;
+
+ if ( position->x < left )
+ {
+ left = position->x;
+ }
+ if ( position->x > right )
+ {
+ right = position->x;
+ }
+ if ( position->y < top )
+ {
+ top = position->y;
+ }
+ if ( position->y > bottom )
+ {
+ bottom = position->y;
+ }
+ if ( position->z > far )
+ {
+ far = position->z;
+ }
+ if ( position->z < near )
+ {
+ near = position->z;
+ }
+ }
+ halfExtents = Vector3( ( right - left ) * 0.5f, ( bottom - top ) * 0.5f, ( far - near ) * 0.5f );
+ center = Vector3( halfExtents.x + left , halfExtents.y + top, halfExtents.z + near );
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ mCenter.Bake( 0, center );
+ mCenter.Bake( 1, center );
+ mHalfExtents.Bake( 0, halfExtents );
+ mHalfExtents.Bake( 1, halfExtents );
+
+ float radius = halfExtents.x;
+ if ( radius < halfExtents.y )
+ {
+ radius = halfExtents.y;
+ }
+ mRadius.SetInitial( radius );
+ }
+ }
+}
+
void Geometry::ConnectToSceneGraph( SceneController& sceneController, BufferIndex bufferIndex )
{
}
virtual void ResetDefaultProperties( BufferIndex updateBufferIndex );
private:
+
+ /**
+ * @brief Calculate the extents of geometry contained in a vertex buffer.
+ *
+ * @param[in] vertexBuffer pointer to a vertex buffer.
+ */
+ void CalculateExtents( PropertyBuffer* vertexBuffer );
+
Vector<PropertyBuffer*> mVertexBuffers; ///< The vertex buffers
PropertyBuffer* mIndexBuffer; ///< The index buffer if required
ConnectionChangePropagator mConnectionObservers;
public: // Properties
- AnimatableProperty<Vector3> mCenter;
- AnimatableProperty<Vector3> mHalfExtents;
- DoubleBufferedProperty<int> mGeometryType;
- DoubleBufferedProperty<bool> mRequiresDepthTest;
+ AnimatableProperty<Vector3> mCenter;
+ AnimatableProperty<Vector3> mHalfExtents;
+ AnimatableProperty<float> mRadius;
+ DoubleBufferedProperty<int> mGeometryType;
+ DoubleBufferedProperty<bool> mRequiresDepthTest;
};
inline void AddVertexBufferMessage( EventThreadServices& eventThreadServices , const Geometry& geometry, const PropertyBuffer& vertexBuffer )
#include <dali/internal/update/manager/prepare-render-instructions.h>
// INTERNAL INCLUDES
+#include <dali/public-api/shader-effects/shader-effect.h>
#include <dali/integration-api/debug.h>
#include <dali/internal/event/actors/layer-impl.h> // for the default sorting function
+#include <dali/internal/update/effects/scene-graph-material.h>
+#include <dali/internal/update/geometry/scene-graph-geometry.h>
+#include <dali/internal/update/node-attachments/scene-graph-renderer-attachment.h>
#include <dali/internal/update/resources/resource-manager-declarations.h>
#include <dali/internal/update/manager/sorted-layers.h>
#include <dali/internal/update/render-tasks/scene-graph-render-task.h>
#include <dali/internal/render/common/render-tracker.h>
#include <dali/internal/render/common/render-instruction.h>
#include <dali/internal/render/common/render-instruction-container.h>
+#include <dali/internal/render/shaders/scene-graph-shader.h>
#include <dali/internal/render/renderers/scene-graph-renderer.h>
namespace
inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
RenderList& renderList,
RenderableAttachment& renderable,
- const Matrix& viewMatrix )
+ const Matrix& viewMatrix,
+ SceneGraph::CameraAttachment& cameraAttachment )
{
- const Renderer& renderer = renderable.GetRenderer();
+ // Check for cull against view frustum
+ Matrix mvm;
+ bool inside = true;
- // Get the next free RenderItem
- RenderItem& item = renderList.GetNextFreeItem();
- item.SetRenderer( const_cast< Renderer* >( &renderer ) );
- item.SetDepthIndex( renderable.GetDepthIndex(updateBufferIndex) );
+ const Node& parentNode = renderable.GetParent();
+ const Matrix& worldMatrix = parentNode.GetWorldMatrix( updateBufferIndex );
+ Matrix::Multiply( mvm, worldMatrix, viewMatrix );
- // calculate MV matrix onto the item
- Matrix& modelViewMatrix = item.GetModelViewMatrix();
- const Matrix& worldMatrix = renderable.GetParent().GetWorldMatrix( updateBufferIndex );
+ if ( RendererAttachment* rendererAttachment = dynamic_cast< RendererAttachment* >( &renderable ) )
+ {
+ if ( rendererAttachment->GetMaterial().GetShader()->GeometryHintEnabled( Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY ) )
+ {
+ // Get the geometry extents for frustum checking
+ const Vector3& position = worldMatrix.GetTranslation3();
+ const Geometry& geometry = rendererAttachment->GetGeometry();
+ const Vector3& localCenter = geometry.mCenter[ updateBufferIndex ];
+ const Vector3& size = parentNode.GetSize( updateBufferIndex );
+ Vector3 center = position + ( localCenter * size );
+
+ // If the size components are all the same, then we can do a quick bounding sphere check
+ if ( fabsf( size.x - size.y ) <= Math::MACHINE_EPSILON_1 * size.x )
+ {
+ inside = cameraAttachment.CheckSphereInFrustum( updateBufferIndex, center, geometry.mRadius[ updateBufferIndex ] * size.x );
+ }
- Matrix::Multiply( modelViewMatrix, worldMatrix, viewMatrix );
+ if ( inside )
+ {
+ // Check against AABB of model
+ inside = cameraAttachment.CheckAABBInFrustum( updateBufferIndex, center, geometry.mHalfExtents[ updateBufferIndex ] * size );
+ }
+ }
+ }
+
+ if ( inside )
+ {
+ // Get the next free RenderItem
+ RenderItem& item = renderList.GetNextFreeItem();
+ const Renderer& renderer = renderable.GetRenderer();
+ item.SetRenderer( const_cast< Renderer* >( &renderer ) );
+ item.SetDepthIndex( renderable.GetDepthIndex(updateBufferIndex) );
+
+ // save MV matrix onto the item
+ Matrix& modelViewMatrix = item.GetModelViewMatrix();
+ modelViewMatrix = mvm;
+ }
}
/**
inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
RenderList& renderList,
RenderableAttachmentContainer& attachments,
- const Matrix& viewMatrix )
+ const Matrix& viewMatrix,
+ SceneGraph::CameraAttachment& cameraAttachment )
{
DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
for ( RenderableAttachmentIter iter = attachments.begin(); iter != endIter; ++iter )
{
RenderableAttachment& attachment = **iter;
- AddRendererToRenderList( updateBufferIndex, renderList, attachment, viewMatrix );
+ AddRendererToRenderList( updateBufferIndex, renderList, attachment, viewMatrix, cameraAttachment );
DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " List[%d].renderer = %p\n", index, &(attachment.GetRenderer()));
index++;
* @param updateBufferIndex to use
* @param layer to get the renderers from
* @param viewmatrix for the camera from rendertask
+ * @param cameraAttachment to use the view frustum
* @param transparentRenderersExist is true if there is transparent renderers in this layer
* @param stencilRenderablesExist is true if there are stencil renderers on this layer
* @param instruction to fill in
inline void AddOpaqueRenderers( BufferIndex updateBufferIndex,
Layer& layer,
const Matrix& viewMatrix,
+ SceneGraph::CameraAttachment& cameraAttachment,
bool transparentRenderablesExist,
bool stencilRenderablesExist,
RenderInstruction& instruction,
return;
}
}
- AddRenderersToRenderList( updateBufferIndex, opaqueRenderList, layer.opaqueRenderables, viewMatrix );
+ AddRenderersToRenderList( updateBufferIndex, opaqueRenderList, layer.opaqueRenderables, viewMatrix, cameraAttachment );
// opaque flags can only be set after renderers are added
SetOpaqueRenderFlags(opaqueRenderList, transparentRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
}
}
-
/**
* Sort transparent render items
* @param transparentRenderList to sort
inline void AddTransparentRenderers( BufferIndex updateBufferIndex,
Layer& layer,
const Matrix& viewMatrix,
+ SceneGraph::CameraAttachment& cameraAttachment,
bool opaqueRenderablesExist,
bool stencilRenderablesExist,
RenderInstruction& instruction,
}
transparentRenderList.SetSourceLayer( &layer );
- AddRenderersToRenderList( updateBufferIndex, transparentRenderList, layer.transparentRenderables, viewMatrix );
+ AddRenderersToRenderList( updateBufferIndex, transparentRenderList, layer.transparentRenderables, viewMatrix, cameraAttachment );
// sorting is only needed if more than 1 item
if( renderableCount > 1 )
inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
Layer& layer,
const Matrix& viewMatrix,
+ SceneGraph::CameraAttachment& cameraAttachment,
bool stencilRenderablesExist,
RenderInstruction& instruction,
bool tryReuseRenderList )
return;
}
}
- AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix );
+ AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix, cameraAttachment );
}
/**
inline void AddStencilRenderers( BufferIndex updateBufferIndex,
Layer& layer,
const Matrix& viewMatrix,
+ SceneGraph::CameraAttachment& cameraAttachment,
RenderInstruction& instruction,
bool tryReuseRenderList )
{
return;
}
}
- AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix );
+ AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix, cameraAttachment );
}
/**
bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
+ SceneGraph::CameraAttachment& cameraAttachment = renderTask.GetCameraAttachment();
const SortedLayersIter endIter = sortedLayers.end();
for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
if( stencilRenderablesExist &&
( opaqueRenderablesExist || transparentRenderablesExist || overlayRenderablesExist ) )
{
- AddStencilRenderers( updateBufferIndex, layer, viewMatrix, instruction, tryReuseRenderList );
+ AddStencilRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, instruction, tryReuseRenderList );
}
if ( opaqueRenderablesExist )
AddOpaqueRenderers( updateBufferIndex,
layer,
viewMatrix,
+ cameraAttachment,
transparentRenderablesExist,
stencilRenderablesExist,
instruction,
AddTransparentRenderers( updateBufferIndex,
layer,
viewMatrix,
+ cameraAttachment,
opaqueRenderablesExist,
stencilRenderablesExist,
instruction,
if ( overlayRenderablesExist )
{
- AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, stencilRenderablesExist,
+ AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, stencilRenderablesExist,
instruction, tryReuseRenderList );
}
}
{
// either has actually changed so recalculate
Matrix::Multiply( mInverseViewProjection[ updateBufferIndex ], mViewMatrix[ updateBufferIndex ], mProjectionMatrix[ updateBufferIndex ] );
+ UpdateFrustum( updateBufferIndex );
+
// ignore the error, if the view projection is incorrect (non inversible) then you will have tough times anyways
static_cast< void >( mInverseViewProjection[ updateBufferIndex ].Invert() );
}
else if( viewUpdateCount == COPY_PREVIOUS_MATRIX || projectionUpdateCount == COPY_PREVIOUS_MATRIX )
{
// neither has actually changed, but we might copied previous frames value so need to
- // copy the previous inverse as well
+ // copy the previous inverse and frustum as well
mInverseViewProjection[updateBufferIndex] = mInverseViewProjection[updateBufferIndex ? 0 : 1];
+ mFrustum[ updateBufferIndex ] = mFrustum[ updateBufferIndex ? 0 : 1 ];
}
}
return retval;
}
+void CameraAttachment::UpdateFrustum( BufferIndex updateBufferIndex, bool normalize )
+{
+
+ // Extract the clip matrix planes
+ Matrix clipMatrix;
+ Matrix::Multiply( clipMatrix, mViewMatrix[ updateBufferIndex ], mProjectionMatrix[ updateBufferIndex ] );
+
+ const float* cm = clipMatrix.AsFloat();
+ FrustumPlanes& planes = mFrustum[ updateBufferIndex ];
+
+ // Left
+ planes.mPlanes[ 0 ].mNormal.x = cm[ 3 ] + cm[ 0 ]; // column 4 + column 1
+ planes.mPlanes[ 0 ].mNormal.y = cm[ 7 ] + cm[ 4 ];
+ planes.mPlanes[ 0 ].mNormal.z = cm[ 11 ] + cm[ 8 ];
+ planes.mPlanes[ 0 ].mDistance = cm[ 15 ] + cm[ 12 ];
+
+ // Right
+ planes.mPlanes[ 1 ].mNormal.x = cm[ 3 ] - cm[ 0 ]; // column 4 - column 1
+ planes.mPlanes[ 1 ].mNormal.y = cm[ 7 ] - cm[ 4 ];
+ planes.mPlanes[ 1 ].mNormal.z = cm[ 11 ] - cm[ 8 ];
+ planes.mPlanes[ 1 ].mDistance = cm[ 15 ] - cm[ 12 ];
+
+ // Bottom
+ planes.mPlanes[ 2 ].mNormal.x = cm[ 3 ] + cm[ 1 ]; // column 4 + column 2
+ planes.mPlanes[ 2 ].mNormal.y = cm[ 7 ] + cm[ 5 ];
+ planes.mPlanes[ 2 ].mNormal.z = cm[ 11 ] + cm[ 9 ];
+ planes.mPlanes[ 2 ].mDistance = cm[ 15 ] + cm[ 13 ];
+
+ // Top
+ planes.mPlanes[ 3 ].mNormal.x = cm[ 3 ] - cm[ 1 ]; // column 4 - column 2
+ planes.mPlanes[ 3 ].mNormal.y = cm[ 7 ] - cm[ 5 ];
+ planes.mPlanes[ 3 ].mNormal.z = cm[ 11 ] - cm[ 9 ];
+ planes.mPlanes[ 3 ].mDistance = cm[ 15 ] - cm[ 13 ];
+
+ // Near
+ planes.mPlanes[ 4 ].mNormal.x = cm[ 3 ] + cm[ 2 ]; // column 4 + column 3
+ planes.mPlanes[ 4 ].mNormal.y = cm[ 7 ] + cm[ 6 ];
+ planes.mPlanes[ 4 ].mNormal.z = cm[ 11 ] + cm[ 10 ];
+ planes.mPlanes[ 4 ].mDistance = cm[ 15 ] + cm[ 14 ];
+
+ // Far
+ planes.mPlanes[ 5 ].mNormal.x = cm[ 3 ] - cm[ 2 ]; // column 4 - column 3
+ planes.mPlanes[ 5 ].mNormal.y = cm[ 7 ] - cm[ 6 ];
+ planes.mPlanes[ 5 ].mNormal.z = cm[ 11 ] - cm[ 10 ];
+ planes.mPlanes[ 5 ].mDistance = cm[ 15 ] - cm[ 14 ];
+
+ if ( normalize )
+ {
+ for ( unsigned int i = 0; i < 6; ++i )
+ {
+ // Normalize planes to ensure correct bounding distance checking
+ Plane& plane = planes.mPlanes[ i ];
+ float l = 1.0f / plane.mNormal.Length();
+ plane.mNormal *= l;
+ plane.mDistance *= l;
+ }
+ }
+ mFrustum[ updateBufferIndex ? 0 : 1 ] = planes;
+}
+
+bool CameraAttachment::CheckSphereInFrustum( BufferIndex bufferIndex, const Vector3& origin, float radius )
+{
+ const FrustumPlanes& planes = mFrustum[ bufferIndex ];
+ for ( uint32_t i = 0; i < 6; ++i )
+ {
+ if ( ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( origin ) ) < -radius )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CameraAttachment::CheckAABBInFrustum( BufferIndex bufferIndex, const Vector3& origin, const Vector3& halfExtents )
+{
+ const FrustumPlanes& planes = mFrustum[ bufferIndex ];
+ Vector3 tln = origin + Vector3( -halfExtents );
+ Vector3 trn = origin + Vector3( halfExtents.x, -halfExtents.y, -halfExtents.z );
+ Vector3 bln = origin + Vector3( -halfExtents.x, halfExtents.y, -halfExtents.z );
+ Vector3 brn = origin + Vector3( halfExtents.x, halfExtents.y, -halfExtents.z );
+ Vector3 tlf = origin + Vector3( -halfExtents.x, -halfExtents.y, halfExtents.z );
+ Vector3 trf = origin + Vector3( halfExtents.x, -halfExtents.y, halfExtents.z );
+ Vector3 blf = origin + Vector3( -halfExtents.x, halfExtents.y, halfExtents.z );
+ Vector3 brf = origin + Vector3( halfExtents.x, halfExtents.y, halfExtents.z );
+
+ for ( uint32_t i = 0; i < 6; ++i )
+ {
+ if ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( tln ) >= 0 )
+ {
+ continue;
+ }
+
+ if ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( trn ) >= 0 )
+ {
+ continue;
+ }
+
+ if ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( bln ) >= 0 )
+ {
+ continue;
+ }
+
+ if ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( brn ) >= 0 )
+ {
+ continue;
+ }
+
+ if ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( tlf ) >= 0 )
+ {
+ continue;
+ }
+
+ if ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( trf ) >= 0 )
+ {
+ continue;
+ }
+
+ if ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( blf ) >= 0 )
+ {
+ continue;
+ }
+
+ if ( planes.mPlanes[ i ].mDistance + planes.mPlanes[ i ].mNormal.Dot( brf ) >= 0 )
+ {
+ continue;
+ }
+ return false;
+ }
+ return true;
+}
+
unsigned int CameraAttachment::UpdateProjection( BufferIndex updateBufferIndex )
{
unsigned int retval( mUpdateProjectionFlag );
static const Vector3 DEFAULT_TARGET_POSITION;
/**
+ * Plane equation container for a plane of the view frustum
+ */
+ struct Plane
+ {
+ Vector3 mNormal;
+ float mDistance;
+ };
+
+ /**
+ * @brief Container for six planes in a view frustum
+ */
+ struct FrustumPlanes
+ {
+ Plane mPlanes[ 6 ];
+ };
+
+ /**
* Construct a new CameraAttachment.
* @return a new camera.
*/
const Matrix& GetViewMatrix( BufferIndex bufferIndex ) const;
/**
+ * @brief Check to see if a sphere lies within the view frustum.
+ *
+ * @param bufferIndex The buffer to read from.
+ * @param origin The world position center of the sphere to check.
+ * @param radius The length of the sphere radius in world scale.
+ *
+ * @return false if the sphere lies outside of the frustum.
+ */
+ bool CheckSphereInFrustum( BufferIndex bufferIndex, const Vector3& origin, float radius );
+
+ /**
+ * @brief Check to see if a bounding box lies within the view frustum.
+ *
+ * @param bufferIndex The buffer to read from.
+ * @param origin the world position center of the cubeoid to check.
+ * @param extents The half length of the cubeoid in world co-ordinates in each axis.
+ *
+ * @return false if the cubeoid lies outside of the frustum.
+ */
+ bool CheckAABBInFrustum( BufferIndex bufferIndex, const Vector3& origin, const Vector3& extents );
+
+ /**
* Retrieve the projection-matrix; this is double buffered for input handling.
* @param[in] bufferIndex The buffer to read from.
* @return The projection-matrix.
private:
+ /**
+ * @brief Extracts the frustum planes.
+ *
+ * @param[in] bufferIndex The current update buffer index.
+ * @param[in] normalize will normalize plane equation coefficients by default.
+ */
+ void UpdateFrustum( BufferIndex updateBufferIndex, bool normalize = true );
+
+
unsigned int mUpdateViewFlag; ///< This is non-zero if the view matrix requires an update
unsigned int mUpdateProjectionFlag; ///< This is non-zero if the projection matrix requires an update
InheritedMatrix mViewMatrix; ///< The view-matrix; this is double buffered for input handling.
InheritedMatrix mProjectionMatrix; ///< The projection-matrix; this is double buffered for input handling.
- DoubleBuffered< Matrix > mInverseViewProjection;///< Inverted viewprojection; double buffered for input handling
+ DoubleBuffered< FrustumPlanes > mFrustum; ///< Clipping frustum; double buffered for input handling
+ DoubleBuffered< Matrix > mInverseViewProjection; ///< Inverted viewprojection; double buffered for input handling
};
#include <dali/internal/update/resources/resource-manager.h>
#include <dali/internal/update/resources/complete-status-manager.h>
#include <dali/internal/update/nodes/node.h>
-#include <dali/internal/update/node-attachments/scene-graph-camera-attachment.h>
#include <dali/internal/render/common/render-instruction.h>
#include <dali/internal/update/render-tasks/scene-graph-render-task-debug.h>
return mCameraAttachment->GetViewMatrix( bufferIndex );
}
+SceneGraph::CameraAttachment& RenderTask::GetCameraAttachment() const
+{
+ DALI_ASSERT_DEBUG( NULL != mCameraAttachment );
+ return *mCameraAttachment;
+}
+
const Matrix& RenderTask::GetProjectionMatrix( BufferIndex bufferIndex ) const
{
DALI_ASSERT_DEBUG( NULL != mCameraAttachment );
const Matrix& GetViewMatrix( BufferIndex bufferIndex ) const;
/**
+ * @brief Retrieve the camera attachment.
+ * @pre GetCameraNode() returns a node with valid CameraAttachment.
+ *
+ * @return The camera attachment.
+ */
+ SceneGraph::CameraAttachment& GetCameraAttachment() const;
+
+ /**
* Retrieve the projection-matrix; this is double buffered for input handling.
* @pre GetCameraNode() returns a node with valid CameraAttachment.
* @param[in] bufferIndex The buffer to read from.