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.
OpenGl_BVHTreeSelector::OpenGl_BVHTreeSelector()
: myIsProjectionParallel (Standard_True),
myCamScaleInv (1.0),
- myDistCull (-1.0),
- myPixelSize (1.0),
- mySizeCull2 (-1.0)
+ myPixelSize (1.0)
{
//
}
// 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;
}
}
// 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;
}
}
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;
-}
//! view volume.
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_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; }
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.
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
};
myNbStructures (0),
myBVHPrimitivesTrsfPers (theBuilder),
myBVHIsLeftChildQueuedFirst (Standard_True),
- myIsBVHPrimitivesNeedsReset (Standard_False)
+ myIsBVHPrimitivesNeedsReset (Standard_False),
+ myIsCulled (Standard_False)
{
myIsBoundingBoxNeedsReset[0] = myIsBoundingBoxNeedsReset[1] = true;
}
// function : InvalidateBVHData
// purpose :
// =======================================================================
-void OpenGl_Layer::InvalidateBVHData() const
+void OpenGl_Layer::InvalidateBVHData()
{
myIsBVHPrimitivesNeedsReset = Standard_True;
}
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;
}
}
// =======================================================================
-// 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)
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)
{
}
// render priority list
- theWorkspace->IsCullingEnabled() ? renderTraverse (theWorkspace) : renderAll (theWorkspace);
+ renderAll (theWorkspace);
if (hasLocalCS)
{
//! 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
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;
//! 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.
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;
//! 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
aLayer.SetLayerSettings (theSettings);
}
+//=======================================================================
+//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 :
{
aClearDepthLayer = aLayerIter.Index();
}
- if (aLayer.NbStructures() < 1)
+ if (aLayer.IsCulled())
{
continue;
}
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,
//! 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.
//! 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
// 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)
myRaytraceInitStatus == OpenGl_RT_FAIL ||
aCtx->IsFeedback();
+ myZLayers.UpdateCulling (myWorkspace, theToDrawImmediate);
+
if (!toRenderGL)
{
toRenderGL = !initRaytraceResources (aCtx) ||