View frustum culling in update. 42/39342/19
authorRichard Underhill <r.underhill@partner.samsung.com>
Fri, 29 May 2015 12:39:00 +0000 (13:39 +0100)
committerFrancisco Santos <f1.santos@samsung.com>
Tue, 9 Jun 2015 09:57:15 +0000 (02:57 -0700)
Change-Id: I6f2d1ccfddb703640d88619be75fd91562f8b6cd
Signed-off-by: Richard Underhill <r.underhill@partner.samsung.com>
automated-tests/src/dali-internal/CMakeLists.txt
automated-tests/src/dali-internal/utc-Dali-Internal-FrustumCulling.cpp [new file with mode: 0644]
dali/internal/update/geometry/scene-graph-geometry.cpp
dali/internal/update/geometry/scene-graph-geometry.h
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/render-tasks/scene-graph-render-task.cpp
dali/internal/update/render-tasks/scene-graph-render-task.h

index 082aff5..049dd3f 100644 (file)
@@ -26,6 +26,7 @@ SET(TC_SOURCES
         utc-Dali-Internal-FixedSizeMemoryPool.cpp
         utc-Dali-Internal-MemoryPoolObjectAllocator.cpp
         utc-Dali-Internal-RelayoutController.cpp
+        utc-Dali-Internal-FrustumCulling.cpp
 )
 
 LIST(APPEND TC_SOURCES
diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-FrustumCulling.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-FrustumCulling.cpp
new file mode 100644 (file)
index 0000000..5145f83
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * 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
index 42488be..6dd928d 100644 (file)
@@ -27,6 +27,7 @@ Geometry::Geometry()
 : mIndexBuffer( NULL ),
   mCenter(),
   mHalfExtents(),
+  mRadius( 0.0f ),
   mGeometryType(Dali::Geometry::TRIANGLES),
   mRequiresDepthTest(false)
 {
@@ -45,6 +46,7 @@ Geometry::~Geometry()
 void Geometry::AddVertexBuffer( PropertyBuffer* vertexBuffer )
 {
   mVertexBuffers.PushBack( vertexBuffer );
+  CalculateExtents( vertexBuffer );
   vertexBuffer->AddUniformMapObserver(*this);
   mConnectionObservers.ConnectionsChanged(*this);
 }
@@ -120,12 +122,140 @@ void Geometry::ResetDefaultProperties( BufferIndex updateBufferIndex )
   // 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 )
 {
 }
index 4cd4384..fe613a4 100644 (file)
@@ -150,15 +150,24 @@ protected: // From PropertyOwner
   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 )
index 27c074c..dde9c68 100644 (file)
 #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>
@@ -30,6 +34,7 @@
 #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
@@ -157,20 +162,54 @@ inline void SetStencilRenderFlags( RenderList& renderList )
 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;
+  }
 }
 
 /**
@@ -183,7 +222,8 @@ inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
 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");
 
@@ -193,7 +233,7 @@ inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
   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++;
@@ -350,6 +390,7 @@ inline void SortOpaqueRenderItems(
  * @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
@@ -358,6 +399,7 @@ inline void SortOpaqueRenderItems(
 inline void AddOpaqueRenderers( BufferIndex updateBufferIndex,
                                 Layer& layer,
                                 const Matrix& viewMatrix,
+                                SceneGraph::CameraAttachment& cameraAttachment,
                                 bool transparentRenderablesExist,
                                 bool stencilRenderablesExist,
                                 RenderInstruction& instruction,
@@ -379,7 +421,7 @@ inline void AddOpaqueRenderers( BufferIndex updateBufferIndex,
       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() );
@@ -391,7 +433,6 @@ inline void AddOpaqueRenderers( BufferIndex updateBufferIndex,
   }
 }
 
-
 /**
  * Sort transparent render items
  * @param transparentRenderList to sort
@@ -477,6 +518,7 @@ inline void SortTransparentRenderItems( BufferIndex bufferIndex, RenderList& tra
 inline void AddTransparentRenderers( BufferIndex updateBufferIndex,
                                      Layer& layer,
                                      const Matrix& viewMatrix,
+                                     SceneGraph::CameraAttachment& cameraAttachment,
                                      bool opaqueRenderablesExist,
                                      bool stencilRenderablesExist,
                                      RenderInstruction& instruction,
@@ -500,7 +542,7 @@ inline void AddTransparentRenderers( BufferIndex updateBufferIndex,
   }
   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 )
@@ -521,6 +563,7 @@ inline void AddTransparentRenderers( BufferIndex updateBufferIndex,
 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
                                  Layer& layer,
                                  const Matrix& viewMatrix,
+                                 SceneGraph::CameraAttachment& cameraAttachment,
                                  bool stencilRenderablesExist,
                                  RenderInstruction& instruction,
                                  bool tryReuseRenderList )
@@ -537,7 +580,7 @@ inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
       return;
     }
   }
-  AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix );
+  AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix, cameraAttachment );
 }
 
 /**
@@ -551,6 +594,7 @@ inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
                                  Layer& layer,
                                  const Matrix& viewMatrix,
+                                 SceneGraph::CameraAttachment& cameraAttachment,
                                  RenderInstruction& instruction,
                                  bool tryReuseRenderList )
 {
@@ -566,7 +610,7 @@ inline void AddStencilRenderers( BufferIndex updateBufferIndex,
       return;
     }
   }
-  AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix );
+  AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix, cameraAttachment );
 }
 
 /**
@@ -592,6 +636,7 @@ void PrepareRenderInstruction( BufferIndex updateBufferIndex,
   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 )
@@ -608,7 +653,7 @@ void PrepareRenderInstruction( BufferIndex updateBufferIndex,
     if( stencilRenderablesExist &&
         ( opaqueRenderablesExist || transparentRenderablesExist || overlayRenderablesExist ) )
     {
-      AddStencilRenderers( updateBufferIndex, layer, viewMatrix, instruction, tryReuseRenderList );
+      AddStencilRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, instruction, tryReuseRenderList );
     }
 
     if ( opaqueRenderablesExist )
@@ -616,6 +661,7 @@ void PrepareRenderInstruction( BufferIndex updateBufferIndex,
       AddOpaqueRenderers( updateBufferIndex,
                           layer,
                           viewMatrix,
+                          cameraAttachment,
                           transparentRenderablesExist,
                           stencilRenderablesExist,
                           instruction,
@@ -628,6 +674,7 @@ void PrepareRenderInstruction( BufferIndex updateBufferIndex,
       AddTransparentRenderers( updateBufferIndex,
                                layer,
                                viewMatrix,
+                               cameraAttachment,
                                opaqueRenderablesExist,
                                stencilRenderablesExist,
                                instruction,
@@ -640,7 +687,7 @@ void PrepareRenderInstruction( BufferIndex updateBufferIndex,
 
     if ( overlayRenderablesExist )
     {
-      AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, stencilRenderablesExist,
+      AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, stencilRenderablesExist,
                            instruction, tryReuseRenderList );
     }
   }
index 5f8c59e..e62a7d8 100644 (file)
@@ -333,14 +333,17 @@ void CameraAttachment::Update( BufferIndex updateBufferIndex, const Node& owning
   {
     // 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 ];
   }
 }
 
@@ -388,6 +391,137 @@ unsigned int CameraAttachment::UpdateViewMatrix( BufferIndex updateBufferIndex,
   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 );
index 97da909..2dccea4 100644 (file)
@@ -67,6 +67,23 @@ public:
   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.
    */
@@ -181,6 +198,28 @@ public:
   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.
@@ -250,6 +289,15 @@ private:
 
 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
 
@@ -272,7 +320,8 @@ public:  // PROPERTIES
   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
 
 };
 
index 8ed7f74..379cb39 100644 (file)
@@ -23,7 +23,6 @@
 #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>
@@ -404,6 +403,12 @@ const Matrix& RenderTask::GetViewMatrix( BufferIndex bufferIndex ) const
   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 );
index 76af939..c1f0796 100644 (file)
@@ -281,6 +281,14 @@ public:
   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.