0028760: Visualization, TKOpenGl - avoid excessive frustum culling traverse within...
authorkgv <kgv@opencascade.com>
Wed, 8 Nov 2017 06:44:27 +0000 (09:44 +0300)
committerkgv <kgv@opencascade.com>
Fri, 10 Nov 2017 04:34:58 +0000 (07:34 +0300)
Culling traverse is no more called implicitly within OpenGl_Layer::Render().
Instead, all layers are traversed at onces within OpenGl_View::render() beforehand.

OpenGl_BVHTreeSelector methods have been renamed to better reflect their meaning.
Non-persistent culling options has been moved to dedicated structure OpenGl_BVHTreeSelector::CullingContext
so that OpenGl_BVHTreeSelector instance can be used for different Layers without modifying its state.

src/OpenGl/OpenGl_BVHTreeSelector.cxx
src/OpenGl/OpenGl_BVHTreeSelector.hxx
src/OpenGl/OpenGl_Layer.cxx
src/OpenGl/OpenGl_Layer.hxx
src/OpenGl/OpenGl_LayerList.cxx
src/OpenGl/OpenGl_LayerList.hxx
src/OpenGl/OpenGl_Structure.hxx
src/OpenGl/OpenGl_View.hxx
src/OpenGl/OpenGl_View_Redraw.cxx

index 644b429..b6d9942 100644 (file)
@@ -26,9 +26,7 @@
 OpenGl_BVHTreeSelector::OpenGl_BVHTreeSelector()
 : myIsProjectionParallel (Standard_True),
   myCamScaleInv (1.0),
-  myDistCull (-1.0),
-  myPixelSize (1.0),
-  mySizeCull2 (-1.0)
+  myPixelSize (1.0)
 {
   //
 }
@@ -166,14 +164,15 @@ Standard_Real OpenGl_BVHTreeSelector::SignedPlanePointDistance (const OpenGl_Vec
 // function : SetCullingDistance
 // purpose  :
 // =======================================================================
-void OpenGl_BVHTreeSelector::SetCullingDistance (Standard_Real theDistance)
+void OpenGl_BVHTreeSelector::SetCullingDistance (CullingContext& theCtx,
+                                                 Standard_Real theDistance) const
 {
-  myDistCull = -1.0;
+  theCtx.DistCull = -1.0;
   if (!myIsProjectionParallel)
   {
-    myDistCull = theDistance > 0.0 && !Precision::IsInfinite (theDistance)
-               ? theDistance
-               : -1.0;
+    theCtx.DistCull = theDistance > 0.0 && !Precision::IsInfinite (theDistance)
+                    ? theDistance
+                    : -1.0;
   }
 }
 
@@ -181,13 +180,14 @@ void OpenGl_BVHTreeSelector::SetCullingDistance (Standard_Real theDistance)
 // function : SetCullingSize
 // purpose  :
 // =======================================================================
-void OpenGl_BVHTreeSelector::SetCullingSize (Standard_Real theSize)
+void OpenGl_BVHTreeSelector::SetCullingSize (CullingContext& theCtx,
+                                             Standard_Real theSize) const
 {
-  mySizeCull2 = -1.0;
+  theCtx.SizeCull2 = -1.0;
   if (theSize > 0.0 && !Precision::IsInfinite (theSize))
   {
-    mySizeCull2 = (myPixelSize * theSize) / myCamScaleInv;
-    mySizeCull2 *= mySizeCull2;
+    theCtx.SizeCull2 = (myPixelSize * theSize) / myCamScaleInv;
+    theCtx.SizeCull2 *= theCtx.SizeCull2;
   }
 }
 
@@ -233,84 +233,3 @@ void OpenGl_BVHTreeSelector::CacheClipPtsProjections()
     myMinOrthoProjectionPts[aDim] = aMinProj;
   }
 }
-
-// =======================================================================
-// function : Intersect
-// purpose  : Detects if AABB overlaps view volume using separating axis theorem (SAT)
-// =======================================================================
-Standard_Boolean OpenGl_BVHTreeSelector::Intersect (const OpenGl_Vec3d& theMinPt,
-                                                    const OpenGl_Vec3d& theMaxPt) const
-{
-  //     E1
-  //    |_ E0
-  //   /
-  //    E2
-
-  // E0 test
-  if (theMinPt.x() > myMaxOrthoProjectionPts[0]
-   || theMaxPt.x() < myMinOrthoProjectionPts[0])
-  {
-    return Standard_False;
-  }
-
-  // E1 test
-  if (theMinPt.y() > myMaxOrthoProjectionPts[1]
-   || theMaxPt.y() < myMinOrthoProjectionPts[1])
-  {
-    return Standard_False;
-  }
-
-  // E2 test
-  if (theMinPt.z() > myMaxOrthoProjectionPts[2]
-   || theMaxPt.z() < myMinOrthoProjectionPts[2])
-  {
-    return Standard_False;
-  }
-
-  Standard_Real aBoxProjMax = 0.0, aBoxProjMin = 0.0;
-  const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
-  for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
-  {
-    OpenGl_Vec4d aPlane = myClipPlanes[aPlaneIter];
-    aBoxProjMax = (aPlane.x() > 0.0 ? (aPlane.x() * theMaxPt.x()) : aPlane.x() * theMinPt.x())
-                + (aPlane.y() > 0.0 ? (aPlane.y() * theMaxPt.y()) : aPlane.y() * theMinPt.y())
-                + (aPlane.z() > 0.0 ? (aPlane.z() * theMaxPt.z()) : aPlane.z() * theMinPt.z());
-    if (aBoxProjMax > myMinClipProjectionPts[aPlaneIter]
-     && aBoxProjMax < myMaxClipProjectionPts[aPlaneIter])
-    {
-      continue;
-    }
-
-    aBoxProjMin = (aPlane.x() < 0.0 ? aPlane.x() * theMaxPt.x() : aPlane.x() * theMinPt.x())
-                + (aPlane.y() < 0.0 ? aPlane.y() * theMaxPt.y() : aPlane.y() * theMinPt.y())
-                + (aPlane.z() < 0.0 ? aPlane.z() * theMaxPt.z() : aPlane.z() * theMinPt.z());
-    if (aBoxProjMin > myMaxClipProjectionPts[aPlaneIter]
-     || aBoxProjMax < myMinClipProjectionPts[aPlaneIter])
-    {
-      return Standard_False;
-    }
-  }
-
-  // distance culling - discard node if distance to it's bounding box from camera eye is less than specified culling distance
-  if (myDistCull > 0.0)
-  {
-    // check distance to the bounding sphere as fast approximation
-    const Graphic3d_Vec3d aSphereCenter = (theMinPt + theMaxPt) * 0.5;
-    const Standard_Real   aSphereRadius = (theMaxPt - theMinPt).maxComp() * 0.5;
-    if ((aSphereCenter - myCamEye).Modulus() - aSphereRadius > myDistCull)
-    {
-      return Standard_False;
-    }
-  }
-
-  // size culling - discard node if diagonal of it's bounding box is less than specified culling size
-  if (mySizeCull2 > 0.0)
-  {
-    if ((theMaxPt - theMinPt).SquareModulus() < mySizeCull2)
-    {
-      return Standard_False;
-    }
-  }
-
-  return Standard_True;
-}
index e0815f5..902e194 100644 (file)
 class OpenGl_BVHTreeSelector
 {
 public:
+  //! Auxiliary structure holding non-persistent culling options.
+  struct CullingContext
+  {
+    Standard_Real DistCull;  //!< culling distance
+    Standard_Real SizeCull2; //!< squared culling size
+
+    //! Empty constructor.
+    CullingContext() : DistCull (-1.0), SizeCull2 (-1.0) {}
+  };
+public:
 
   //! Creates an empty selector object with parallel projection type by default.
   Standard_EXPORT OpenGl_BVHTreeSelector();
@@ -38,21 +48,30 @@ public:
                                         Standard_Real theResolutionRatio);
 
   //! Setup distance culling.
-  Standard_EXPORT void SetCullingDistance (Standard_Real theDistance);
+  Standard_EXPORT void SetCullingDistance (CullingContext& theCtx,
+                                           Standard_Real theDistance) const;
 
   //! Setup size culling.
-  Standard_EXPORT void SetCullingSize (Standard_Real theSize);
+  Standard_EXPORT void SetCullingSize (CullingContext& theCtx,
+                                       Standard_Real theSize) const;
 
   //! Caches view volume's vertices projections along its normals and AABBs dimensions.
   //! Must be called at the beginning of each BVH tree traverse loop.
   Standard_EXPORT void CacheClipPtsProjections();
 
-  //! Detects if AABB overlaps view volume using separating axis theorem (SAT).
-  //! @param theMinPt [in] maximum point of AABB.
-  //! @param theMaxPt [in] minimum point of AABB.
-  //! @return Standard_True, if AABB is in viewing area, Standard_False otherwise.
-  Standard_EXPORT Standard_Boolean Intersect (const OpenGl_Vec3d& theMinPt,
-                                              const OpenGl_Vec3d& theMaxPt) const;
+  //! Checks whether given AABB should be entirely culled or not.
+  //! @param theCtx   [in] culling properties
+  //! @param theMinPt [in] maximum point of AABB
+  //! @param theMaxPt [in] minimum point of AABB
+  //! @return Standard_True, if AABB is in viewing area, Standard_False otherwise
+  bool IsCulled (const CullingContext& theCtx,
+                 const OpenGl_Vec3d& theMinPt,
+                 const OpenGl_Vec3d& theMaxPt) const
+  {
+    return isFullOut   (theMinPt, theMaxPt)
+        || isTooDistant(theCtx, theMinPt, theMaxPt)
+        || isTooSmall  (theCtx, theMinPt, theMaxPt);
+  }
 
   //! Return the camera definition.
   const Handle(Graphic3d_Camera)& Camera() const { return myCamera; }
@@ -93,6 +112,93 @@ protected:
   Standard_EXPORT Standard_Real SignedPlanePointDistance (const OpenGl_Vec4d& theNormal,
                                                           const OpenGl_Vec4d& thePnt);
 
+  //! Detects if AABB overlaps view volume using separating axis theorem (SAT).
+  //! @param theMinPt [in] maximum point of AABB.
+  //! @param theMaxPt [in] minimum point of AABB.
+  //! @return FALSE, if AABB is in viewing area, TRUE otherwise.
+  bool isFullOut (const OpenGl_Vec3d& theMinPt,
+                  const OpenGl_Vec3d& theMaxPt) const
+  {
+    //     E1
+    //    |_ E0
+    //   /
+    //    E2
+
+    // E0 test
+    if (theMinPt.x() > myMaxOrthoProjectionPts[0]
+     || theMaxPt.x() < myMinOrthoProjectionPts[0])
+    {
+      return true;
+    }
+
+    // E1 test
+    if (theMinPt.y() > myMaxOrthoProjectionPts[1]
+     || theMaxPt.y() < myMinOrthoProjectionPts[1])
+    {
+      return true;
+    }
+
+    // E2 test
+    if (theMinPt.z() > myMaxOrthoProjectionPts[2]
+     || theMaxPt.z() < myMinOrthoProjectionPts[2])
+    {
+      return true;
+    }
+
+    Standard_Real aBoxProjMax = 0.0, aBoxProjMin = 0.0;
+    const Standard_Integer anIncFactor = myIsProjectionParallel ? 2 : 1;
+    for (Standard_Integer aPlaneIter = 0; aPlaneIter < 5; aPlaneIter += anIncFactor)
+    {
+      OpenGl_Vec4d aPlane = myClipPlanes[aPlaneIter];
+      aBoxProjMax = (aPlane.x() > 0.0 ? (aPlane.x() * theMaxPt.x()) : aPlane.x() * theMinPt.x())
+                  + (aPlane.y() > 0.0 ? (aPlane.y() * theMaxPt.y()) : aPlane.y() * theMinPt.y())
+                  + (aPlane.z() > 0.0 ? (aPlane.z() * theMaxPt.z()) : aPlane.z() * theMinPt.z());
+      if (aBoxProjMax > myMinClipProjectionPts[aPlaneIter]
+       && aBoxProjMax < myMaxClipProjectionPts[aPlaneIter])
+      {
+        continue;
+      }
+
+      aBoxProjMin = (aPlane.x() < 0.0 ? aPlane.x() * theMaxPt.x() : aPlane.x() * theMinPt.x())
+                  + (aPlane.y() < 0.0 ? aPlane.y() * theMaxPt.y() : aPlane.y() * theMinPt.y())
+                  + (aPlane.z() < 0.0 ? aPlane.z() * theMaxPt.z() : aPlane.z() * theMinPt.z());
+      if (aBoxProjMin > myMaxClipProjectionPts[aPlaneIter]
+       || aBoxProjMax < myMinClipProjectionPts[aPlaneIter])
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  //! Returns TRUE if given AABB should be discarded by distance culling criterion.
+  bool isTooDistant (const CullingContext& theCtx,
+                     const OpenGl_Vec3d& theMinPt,
+                     const OpenGl_Vec3d& theMaxPt) const
+  {
+    if (theCtx.DistCull <= 0.0)
+    {
+      return false;
+    }
+
+    // check distance to the bounding sphere as fast approximation
+    const Graphic3d_Vec3d aSphereCenter = (theMinPt + theMaxPt) * 0.5;
+    const Standard_Real   aSphereRadius = (theMaxPt - theMinPt).maxComp() * 0.5;
+    return (aSphereCenter - myCamEye).Modulus() - aSphereRadius > theCtx.DistCull;
+  }
+
+  //! Returns TRUE if given AABB should be discarded by size culling criterion.
+  bool isTooSmall (const CullingContext& theCtx,
+                   const OpenGl_Vec3d& theMinPt,
+                   const OpenGl_Vec3d& theMaxPt) const
+  {
+    if (theCtx.SizeCull2 <= 0.0)
+    {
+      return false;
+    }
+    return (theMaxPt - theMinPt).SquareModulus() < theCtx.SizeCull2;
+  }
+
 protected:
 
   //! Enumerates planes of view volume.
@@ -150,9 +256,7 @@ protected:
 
   Graphic3d_Vec3d myCamEye;      //!< camera eye position for distance culling
   Standard_Real   myCamScaleInv; //!< inverted camera scale for size culling
-  Standard_Real   myDistCull;    //!< culling distance
   Standard_Real   myPixelSize;   //!< pixel size for size culling
-  Standard_Real   mySizeCull2;   //!< squared culling size
 
 };
 
index f5bca3f..e5e94cf 100644 (file)
@@ -34,7 +34,8 @@ OpenGl_Layer::OpenGl_Layer (const Standard_Integer theNbPriorities,
   myNbStructures              (0),
   myBVHPrimitivesTrsfPers     (theBuilder),
   myBVHIsLeftChildQueuedFirst (Standard_True),
-  myIsBVHPrimitivesNeedsReset (Standard_False)
+  myIsBVHPrimitivesNeedsReset (Standard_False),
+  myIsCulled (Standard_False)
 {
   myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
 }
@@ -147,7 +148,7 @@ bool OpenGl_Layer::Remove (const OpenGl_Structure* theStruct,
 // function : InvalidateBVHData
 // purpose  :
 // =======================================================================
-void OpenGl_Layer::InvalidateBVHData() const
+void OpenGl_Layer::InvalidateBVHData()
 {
   myIsBVHPrimitivesNeedsReset = Standard_True;
 }
@@ -429,12 +430,8 @@ void OpenGl_Layer::renderAll (const Handle(OpenGl_Workspace)& theWorkspace) cons
     for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
     {
       const OpenGl_Structure* aStruct = aStructIter.Value();
-      if (!aStruct->IsVisible())
-      {
-        continue;
-      }
-      else if (!aStruct->ViewAffinity.IsNull()
-            && !aStruct->ViewAffinity->IsVisible (aViewId))
+      if (aStruct->IsCulled()
+      || !aStruct->IsVisible (aViewId))
       {
         continue;
       }
@@ -483,51 +480,43 @@ void OpenGl_Layer::updateBVH() const
 }
 
 // =======================================================================
-// function : renderTraverse
+// function : UpdateCulling
 // purpose  :
 // =======================================================================
-void OpenGl_Layer::renderTraverse (const Handle(OpenGl_Workspace)& theWorkspace) const
+void OpenGl_Layer::UpdateCulling (const OpenGl_BVHTreeSelector& theSelector,
+                                  const Standard_Boolean theToTraverse)
 {
   updateBVH();
-  if (myBVHPrimitives        .Size() != 0
-   || myBVHPrimitivesTrsfPers.Size() != 0)
-  {
-    OpenGl_BVHTreeSelector& aSelector = theWorkspace->View()->BVHTreeSelector();
-    aSelector.SetCullingDistance (myLayerSettings.CullingDistance());
-    aSelector.SetCullingSize (myLayerSettings.CullingSize());
-    aSelector.CacheClipPtsProjections();
-    traverse (aSelector);
-  }
 
-  const Standard_Integer aViewId = theWorkspace->View()->Identification();
+  myIsCulled = false;
   for (OpenGl_ArrayOfIndexedMapOfStructure::Iterator aMapIter (myArray); aMapIter.More(); aMapIter.Next())
   {
     const OpenGl_IndexedMapOfStructure& aStructures = aMapIter.Value();
     for (OpenGl_IndexedMapOfStructure::Iterator aStructIter (aStructures); aStructIter.More(); aStructIter.Next())
     {
       const OpenGl_Structure* aStruct = aStructIter.Value();
-      if (aStruct->IsCulled()
-      || !aStruct->IsVisible (aViewId))
-      {
-        continue;
-      }
-
-      aStruct->Render (theWorkspace);
-      aStruct->ResetCullingStatus();
+      aStruct->SetCulled (theToTraverse);
     }
   }
-}
 
-// =======================================================================
-// function : traverse
-// purpose  :
-// =======================================================================
-void OpenGl_Layer::traverse (const OpenGl_BVHTreeSelector& theSelector) const
-{
-  opencascade::handle<BVH_Tree<Standard_Real, 3> > aBVHTree;
+  if (!theToTraverse)
+  {
+    return;
+  }
+  if (myBVHPrimitives        .Size() == 0
+   && myBVHPrimitivesTrsfPers.Size() == 0)
+  {
+    return;
+  }
+
+  myIsCulled = myAlwaysRenderedMap.IsEmpty();
+  OpenGl_BVHTreeSelector::CullingContext aCullCtx;
+  theSelector.SetCullingDistance(aCullCtx, myLayerSettings.CullingDistance());
+  theSelector.SetCullingSize    (aCullCtx, myLayerSettings.CullingSize());
   for (Standard_Integer aBVHTreeIdx = 0; aBVHTreeIdx < 2; ++aBVHTreeIdx)
   {
     const Standard_Boolean isTrsfPers = aBVHTreeIdx == 1;
+    opencascade::handle<BVH_Tree<Standard_Real, 3> > aBVHTree;
     if (isTrsfPers)
     {
       if (myBVHPrimitivesTrsfPers.Size() == 0)
@@ -549,26 +538,23 @@ void OpenGl_Layer::traverse (const OpenGl_BVHTreeSelector& theSelector) const
       aBVHTree = myBVHPrimitives.BVH();
     }
 
-    Standard_Integer aNode = 0; // a root node
-
-    if (!theSelector.Intersect (aBVHTree->MinPoint (0),
-                                aBVHTree->MaxPoint (0)))
+    if (theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (0), aBVHTree->MaxPoint (0)))
     {
       continue;
     }
 
+    myIsCulled = false;
     Standard_Integer aStack[BVH_Constants_MaxTreeDepth];
     Standard_Integer aHead = -1;
+    Standard_Integer aNode = 0; // a root node
     for (;;)
     {
       if (!aBVHTree->IsOuter (aNode))
       {
         const Standard_Integer aLeftChildIdx  = aBVHTree->Child<0> (aNode);
         const Standard_Integer aRightChildIdx = aBVHTree->Child<1> (aNode);
-        const Standard_Boolean isLeftChildIn  = theSelector.Intersect (aBVHTree->MinPoint (aLeftChildIdx),
-                                                                       aBVHTree->MaxPoint (aLeftChildIdx));
-        const Standard_Boolean isRightChildIn = theSelector.Intersect (aBVHTree->MinPoint (aRightChildIdx),
-                                                                       aBVHTree->MaxPoint (aRightChildIdx));
+        const Standard_Boolean isLeftChildIn  = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aLeftChildIdx),  aBVHTree->MaxPoint (aLeftChildIdx));
+        const Standard_Boolean isRightChildIn = !theSelector.IsCulled (aCullCtx, aBVHTree->MinPoint (aRightChildIdx), aBVHTree->MaxPoint (aRightChildIdx));
         if (isLeftChildIn
          && isRightChildIn)
         {
@@ -743,7 +729,7 @@ void OpenGl_Layer::Render (const Handle(OpenGl_Workspace)&   theWorkspace,
   }
 
   // render priority list
-  theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
+  renderAll (theWorkspace);
 
   if (hasLocalCS)
   {
index a74ea43..ee96e8e 100644 (file)
@@ -92,7 +92,7 @@ public:
 
   //! Marks BVH tree for given priority list as dirty and
   //! marks primitive set for rebuild.
-  void InvalidateBVHData() const;
+  void InvalidateBVHData();
 
   //! Marks cached bounding box as obsolete.
   void InvalidateBoundingBox() const
@@ -119,6 +119,14 @@ public:
                                                 const Standard_Integer          theWindowWidth,
                                                 const Standard_Integer          theWindowHeight) const;
 
+  //! Update culling state - should be called before rendering.
+  //! Traverses through BVH tree to determine which structures are in view volume.
+  void UpdateCulling (const OpenGl_BVHTreeSelector& theSelector,
+                      const Standard_Boolean theToTraverse);
+
+  //! Returns TRUE if layer is empty or has been discarded entirely by culling test.
+  bool IsCulled() const { return myNbStructures == 0 || myIsCulled; }
+
   // Render all structures.
   void Render (const Handle(OpenGl_Workspace)&   theWorkspace,
                const OpenGl_GlobalLayerSettings& theDefaultSettings) const;
@@ -134,15 +142,9 @@ protected:
   //! Updates BVH trees if their state has been invalidated.
   void updateBVH() const;
 
-  //! Traverses through BVH tree to determine which structures are in view volume.
-  void traverse (const OpenGl_BVHTreeSelector& theSelector) const;
-
   //! Iterates through the hierarchical list of existing structures and renders them all.
   void renderAll (const Handle(OpenGl_Workspace)& theWorkspace) const;
 
-  //! Iterates through the hierarchical list of existing structures and renders only overlapping ones.
-  void renderTraverse (const Handle(OpenGl_Workspace)& theWorkspace) const;
-
 private:
 
   //! Array of OpenGl_Structures by priority rendered in layer.
@@ -164,7 +166,7 @@ private:
   mutable NCollection_IndexedMap<const OpenGl_Structure*> myAlwaysRenderedMap;
 
   //! Is needed for implementation of stochastic order of BVH traverse.
-  mutable Standard_Boolean myBVHIsLeftChildQueuedFirst;
+  Standard_Boolean myBVHIsLeftChildQueuedFirst;
 
   //! Defines if the primitive set for BVH is outdated.
   mutable Standard_Boolean myIsBVHPrimitivesNeedsReset;
@@ -172,13 +174,12 @@ private:
   //! Defines if the cached bounding box is outdated.
   mutable bool myIsBoundingBoxNeedsReset[2];
 
+  //! Flag indicating that this layer is marked culled as whole
+  bool myIsCulled;
+
   //! Cached layer bounding box.
   mutable Bnd_Box myBoundingBox[2];
 
-public:
-
-  DEFINE_STANDARD_ALLOC
-
 };
 
 #endif //_OpenGl_Layer_Header
index aa361ac..eddee5b 100644 (file)
@@ -510,6 +510,26 @@ void OpenGl_LayerList::SetLayerSettings (const Graphic3d_ZLayerId        theLaye
 }
 
 //=======================================================================
+//function : UpdateCulling
+//purpose  :
+//=======================================================================
+void OpenGl_LayerList::UpdateCulling (const Handle(OpenGl_Workspace)& theWorkspace,
+                                      const Standard_Boolean theToDrawImmediate)
+{
+  const OpenGl_BVHTreeSelector& aSelector = theWorkspace->View()->BVHTreeSelector();
+  for (OpenGl_IndexedLayerIterator anIts (myLayers); anIts.More(); anIts.Next())
+  {
+    OpenGl_Layer& aLayer = *anIts.ChangeValue();
+    if (aLayer.IsImmediate() != theToDrawImmediate)
+    {
+      continue;
+    }
+
+    aLayer.UpdateCulling (aSelector, theWorkspace->IsCullingEnabled());
+  }
+}
+
+//=======================================================================
 //function : Render
 //purpose  :
 //=======================================================================
@@ -588,7 +608,7 @@ void OpenGl_LayerList::Render (const Handle(OpenGl_Workspace)& theWorkspace,
         {
           aClearDepthLayer = aLayerIter.Index();
         }
-        if (aLayer.NbStructures() < 1)
+        if (aLayer.IsCulled())
         {
           continue;
         }
index 1e7848c..bf4063c 100644 (file)
@@ -88,6 +88,10 @@ public:
   void SetLayerSettings (const Graphic3d_ZLayerId        theLayerId,
                          const Graphic3d_ZLayerSettings& theSettings);
 
+  //! Update culling state - should be called before rendering.
+  void UpdateCulling (const Handle(OpenGl_Workspace)& theWorkspace,
+                      const Standard_Boolean theToDrawImmediate);
+
   //! Render this element
   void Render (const Handle(OpenGl_Workspace)& theWorkspace,
                const Standard_Boolean          theToDrawImmediate,
index 11d38ac..e7f679b 100644 (file)
@@ -119,13 +119,10 @@ public:
   //! Releases structure resources.
   virtual void Release (const Handle(OpenGl_Context)& theGlCtx);
 
-  //! Marks structure as not overlapping view volume (as it is by default).
-  void ResetCullingStatus() const
+  //! Marks structure as culled/not culled.
+  void SetCulled (Standard_Boolean theIsCulled) const
   {
-    if (!IsAlwaysRendered())
-    {
-      myIsCulled = Standard_True;
-    }
+    myIsCulled = theIsCulled && !IsAlwaysRendered();
   }
 
   //! Marks structure as overlapping the current view volume one.
index 95adf31..f9e0142 100644 (file)
@@ -336,7 +336,7 @@ public:
 
   //! Returns selector for BVH tree, providing a possibility to store information
   //! about current view volume and to detect which objects are overlapping it.
-  OpenGl_BVHTreeSelector& BVHTreeSelector() { return myBVHSelector; }
+  const OpenGl_BVHTreeSelector& BVHTreeSelector() const { return myBVHSelector; }
 
   //! Returns true if there are immediate structures to display
   bool HasImmediateStructures() const
index b579c52..bc36fcc 100644 (file)
@@ -881,6 +881,7 @@ void OpenGl_View::render (Graphic3d_Camera::Projection theProjection,
   // note that we pass here window dimensions ignoring Graphic3d_RenderingParams::RenderResolutionScale
   myBVHSelector.SetViewVolume (myCamera);
   myBVHSelector.SetViewportSize (myWindow->Width(), myWindow->Height(), myRenderParams.ResolutionRatio());
+  myBVHSelector.CacheClipPtsProjections();
 
   const Handle(OpenGl_ShaderManager)& aManager   = aContext->ShaderManager();
   if (StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index()) != myLastLightSourceState)
@@ -1058,6 +1059,8 @@ void OpenGl_View::renderStructs (Graphic3d_Camera::Projection theProjection,
     myRaytraceInitStatus == OpenGl_RT_FAIL ||
     aCtx->IsFeedback();
 
+  myZLayers.UpdateCulling (myWorkspace, theToDrawImmediate);
+
   if (!toRenderGL)
   {
     toRenderGL = !initRaytraceResources (aCtx) ||