OpenGl_Structure::Render() now checks if structure is entirely clipped to skip rendering at all,
or entirely NOT clipped to disable clipping / capping plane.
OpenGl_ShaderManager now defines dedicated GLSL programs for one and two clipping planes
to optimize rendering on slow hardware.
return aMin1 < aMin2 ? aMin1 : aMin2;
}
+ //! Computes the dot product.
+ Element_t Dot (const NCollection_Vec4& theOther) const
+ {
+ return x() * theOther.x() +
+ y() * theOther.y() +
+ z() * theOther.z() +
+ w() * theOther.w();
+ }
+
//! Compute per-component division by scale factor.
NCollection_Vec4& operator/= (const Element_t theInvFactor)
{
for (; aPlaneIt.More(); aPlaneIt.Next())
{
const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
- if (!Contains (aPlane))
+ PlaneProps* aProps = myPlaneStates.ChangeSeek (aPlane);
+ if (aProps == NULL)
{
continue;
}
- Standard_Integer anID = myPlaneStates.Find (aPlane).ContextID;
- PlaneProps& aProps = myPlaneStates.ChangeFind (aPlane);
- if (aProps.IsEnabled)
+ Standard_Integer anID = aProps->ContextID;
+ if (aProps->IsEnabled)
{
#if !defined(GL_ES_VERSION_2_0)
if (toUseFfp)
const Handle(Graphic3d_ClipPlane)& thePlane,
const Standard_Boolean theIsEnabled)
{
- if (!Contains (thePlane))
- {
- return;
- }
-
- PlaneProps& aProps = myPlaneStates.ChangeFind (thePlane);
- if (theIsEnabled == aProps.IsEnabled)
+ PlaneProps* aProps = myPlaneStates.ChangeSeek (thePlane);
+ if (aProps == NULL
+ || aProps->IsEnabled == theIsEnabled)
{
return;
}
#if !defined(GL_ES_VERSION_2_0)
- GLenum anID = (GLenum)aProps.ContextID;
+ GLenum anID = (GLenum)aProps->ContextID;
const bool toUseFfp = theGlCtx->core11 != NULL
&& theGlCtx->caps->ffpEnable;
#else
}
}
- aProps.IsEnabled = theIsEnabled;
+ aProps->IsEnabled = theIsEnabled;
}
return (myNbClipping + myNbCapping) > 0;
}
+ //! @return number of enabled clipping + capping planes
+ Standard_Integer NbClippingOrCappingOn() const
+ {
+ return myNbClipping + myNbCapping;
+ }
+
public: //! @name clipping state modification commands
//! Add planes to the context clipping at the specified system of coordinates.
//! Standard GLSL program combination bits.
enum OpenGl_ProgramOptions
{
- OpenGl_PO_ClipPlanes = 0x01, //!< handle clipping planes
- OpenGl_PO_Point = 0x02, //!< point marker
- OpenGl_PO_VertColor = 0x04, //!< per-vertex color
- OpenGl_PO_TextureRGB = 0x08, //!< handle RGB texturing
- OpenGl_PO_TextureA = 0x10, //!< handle Alpha texturing
- OpenGl_PO_TextureEnv = 0x20, //!< handle environment map
- OpenGl_PO_StippleLine = 0x40, //!< stipple line
- OpenGl_PO_NB = 0x80 //!< overall number of combinations
+ OpenGl_PO_Point = 0x001, //!< point marker
+ OpenGl_PO_VertColor = 0x002, //!< per-vertex color
+ OpenGl_PO_TextureRGB = 0x004, //!< handle RGB texturing
+ OpenGl_PO_TextureA = 0x008, //!< handle Alpha texturing
+ OpenGl_PO_TextureEnv = 0x010, //!< handle environment map
+ OpenGl_PO_StippleLine = 0x020, //!< stipple line
+ OpenGl_PO_ClipPlanes1 = 0x040, //!< handle 1 clipping plane
+ OpenGl_PO_ClipPlanes2 = 0x080, //!< handle 2 clipping planes
+ OpenGl_PO_ClipPlanesN = 0x100, //!< handle N clipping planes
+ OpenGl_PO_NB = 0x200 //!< overall number of combinations
};
//! Alias to programs array of predefined length
//! Process clipping planes in Fragment Shader.
//! Should be added at the beginning of the main() function.
-const char THE_FRAG_CLIP_PLANES[] =
+const char THE_FRAG_CLIP_PLANES_N[] =
EOL" for (int aPlaneIter = 0; aPlaneIter < occClipPlaneCount; ++aPlaneIter)"
EOL" {"
EOL" vec4 aClipEquation = occClipPlaneEquations[aPlaneIter];"
EOL" }"
EOL" }";
+//! Process 1 clipping plane in Fragment Shader.
+const char THE_FRAG_CLIP_PLANES_1[] =
+ EOL" vec4 aClipEquation0 = occClipPlaneEquations[0];"
+ EOL" if (dot (aClipEquation0.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation0.w < 0.0)"
+ EOL" {"
+ EOL" discard;"
+ EOL" }";
+
+//! Process 2 clipping planes in Fragment Shader.
+const char THE_FRAG_CLIP_PLANES_2[] =
+ EOL" vec4 aClipEquation0 = occClipPlaneEquations[0];"
+ EOL" vec4 aClipEquation1 = occClipPlaneEquations[1];"
+ EOL" if (dot (aClipEquation0.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation0.w < 0.0"
+ EOL" || dot (aClipEquation1.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation1.w < 0.0)"
+ EOL" {"
+ EOL" discard;"
+ EOL" }";
+
}
// =======================================================================
aSrcFragExtraOut += EOL"THE_SHADER_IN vec4 VertColor;";
aSrcFragGetColor = EOL"vec4 getColor(void) { return VertColor; }";
}
- if ((theBits & OpenGl_PO_ClipPlanes) != 0)
+ if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
{
aSrcVertExtraOut +=
EOL"THE_SHADER_OUT vec4 PositionWorld;"
aSrcVertExtraMain +=
EOL" PositionWorld = occModelWorldMatrix * occVertex;"
EOL" Position = occWorldViewMatrix * PositionWorld;";
- aSrcFragExtraMain += THE_FRAG_CLIP_PLANES;
+
+ if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
+ {
+ aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
+ }
+ else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
+ {
+ aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
+ }
+ else
+ {
+ aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
+ }
}
TCollection_AsciiString aSrcVertEndMain;
aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
}
- if ((theBits & OpenGl_PO_ClipPlanes) != 0)
+ if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
{
aSrcVertExtraOut +=
EOL"THE_SHADER_OUT vec4 PositionWorld;"
aSrcVertExtraMain +=
EOL" PositionWorld = aPositionWorld;"
EOL" Position = aPosition;";
- aSrcFragExtraMain += THE_FRAG_CLIP_PLANES;
+
+ if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
+ {
+ aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
+ }
+ else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
+ {
+ aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
+ }
+ else
+ {
+ aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
+ }
}
const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
EOL"vec4 getVertColor(void) { return VertColor; }";
}
- if ((theBits & OpenGl_PO_ClipPlanes) != 0)
+ if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
{
- aSrcFragExtraMain += THE_FRAG_CLIP_PLANES;
+ if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
+ {
+ aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
+ }
+ else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
+ {
+ aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
+ }
+ else
+ {
+ aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
+ }
}
aSrcVert = TCollection_AsciiString()
{
Standard_Integer aBits = 0;
- if (myContext->Clipping().IsClippingOrCappingOn())
+
+ const Standard_Integer aNbPlanes = myContext->Clipping().NbClippingOrCappingOn();
+ if (aNbPlanes > 0)
{
- aBits |= OpenGl_PO_ClipPlanes;
+ aBits |= OpenGl_PO_ClipPlanesN;
+ if (aNbPlanes == 1)
+ {
+ aBits |= OpenGl_PO_ClipPlanes1;
+ }
+ else if (aNbPlanes == 2)
+ {
+ aBits |= OpenGl_PO_ClipPlanes2;
+ }
}
+
if (theEnableEnvMap)
{
// Environment map overwrites material texture
// Set up plane equations for non-structure transformed global model-view matrix
// List of planes to be applied to context state
- NCollection_Handle<Graphic3d_SequenceOfHClipPlane> aUserPlanes;
+ Handle(NCollection_Shared<Graphic3d_SequenceOfHClipPlane>) aUserPlanes, aDisabledPlanes;
// Collect clipping planes of structure scope
if (!myClipPlanes.IsEmpty())
{
- Graphic3d_SequenceOfHClipPlane::Iterator aClippingIter (myClipPlanes);
- for (; aClippingIter.More(); aClippingIter.Next())
+ for (Graphic3d_SequenceOfHClipPlane::Iterator aClippingIter (myClipPlanes); aClippingIter.More(); aClippingIter.Next())
{
const Handle(Graphic3d_ClipPlane)& aClipPlane = aClippingIter.Value();
if (!aClipPlane->IsOn())
if (aUserPlanes.IsNull())
{
- aUserPlanes = new Graphic3d_SequenceOfHClipPlane();
+ aUserPlanes = new NCollection_Shared<Graphic3d_SequenceOfHClipPlane>();
}
-
aUserPlanes->Append (aClipPlane);
}
}
-
- if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
+ if (!aUserPlanes.IsNull())
{
// add planes at loaded view matrix state
aCtx->ChangeClipping().AddWorld (aCtx, *aUserPlanes);
aCtx->ShaderManager()->UpdateClippingState();
}
+ // True if structure is fully clipped
+ bool isClipped = false;
+
+ // Set of clipping planes that do not intersect the structure,
+ // and thus can be disabled to improve rendering performance
+ const Graphic3d_BndBox4f& aBBox = BoundingBox();
+ if (!aCtx->Clipping().Planes().IsEmpty() && aBBox.IsValid() && TransformPersistence.Flags == Graphic3d_TMF_None)
+ {
+ for (Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (aCtx->Clipping().Planes()); aPlaneIt.More(); aPlaneIt.Next())
+ {
+ const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
+ if (!aPlane->IsOn())
+ {
+ continue;
+ }
+
+ // check for clipping
+ const Graphic3d_Vec4d& aPlaneEquation = aPlane->GetEquation();
+ const Graphic3d_Vec4d aMaxPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMax().x() : aBBox.CornerMin().x(),
+ aPlaneEquation.y() > 0.0 ? aBBox.CornerMax().y() : aBBox.CornerMin().y(),
+ aPlaneEquation.z() > 0.0 ? aBBox.CornerMax().z() : aBBox.CornerMin().z(),
+ 1.0);
+ if (aPlaneEquation.Dot (aMaxPnt) < 0.0) // max vertex is outside the half-space
+ {
+ isClipped = true;
+ break;
+ }
+
+ // check for no intersection (e.g. object is "entirely not clipped")
+ const Graphic3d_Vec4d aMinPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMin().x() : aBBox.CornerMax().x(),
+ aPlaneEquation.y() > 0.0 ? aBBox.CornerMin().y() : aBBox.CornerMax().y(),
+ aPlaneEquation.z() > 0.0 ? aBBox.CornerMin().z() : aBBox.CornerMax().z(),
+ 1.0);
+ if (aPlaneEquation.Dot (aMinPnt) > 0.0) // min vertex is inside the half-space
+ {
+ aCtx->ChangeClipping().SetEnabled (aCtx, aPlane, Standard_False);
+ if (aDisabledPlanes.IsNull())
+ {
+ aDisabledPlanes = new NCollection_Shared<Graphic3d_SequenceOfHClipPlane>();
+ if (aUserPlanes.IsNull())
+ {
+ aCtx->ShaderManager()->UpdateClippingState();
+ }
+ }
+ aDisabledPlanes->Append (aPlane);
+ }
+ }
+ }
+
// Render groups
bool hasClosedPrims = false;
- renderGeometry (theWorkspace, hasClosedPrims);
+ if (!isClipped)
+ {
+ renderGeometry (theWorkspace, hasClosedPrims);
+ }
// Reset correction for mirror transform
if (myIsMirrored)
// Render capping for structure groups
if (hasClosedPrims
- && !aCtx->Clipping().Planes().IsEmpty())
+ && aCtx->Clipping().IsCappingOn())
{
OpenGl_CappingAlgo::RenderCapping (theWorkspace, *this);
}
// Revert structure clippings
- if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty())
+ if (!aDisabledPlanes.IsNull())
+ {
+ // enable planes that were previously disabled
+ for (Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (*aDisabledPlanes); aPlaneIt.More(); aPlaneIt.Next())
+ {
+ aCtx->ChangeClipping().SetEnabled (aCtx, aPlaneIt.Value(), Standard_True);
+ }
+ if (aUserPlanes.IsNull())
+ {
+ aCtx->ShaderManager()->RevertClippingState();
+ }
+ }
+ if (!aUserPlanes.IsNull())
{
aCtx->ChangeClipping().Remove (aCtx, *aUserPlanes);