From 1a7ece8f23b613de8bdca410c031dcb898dd1fc8 Mon Sep 17 00:00:00 2001 From: dbp Date: Thu, 18 Aug 2016 19:41:05 +0300 Subject: [PATCH] 0027787: Visualization, TKOpenGl - Optimize rendering by additional check whether the object is fully clipped or not 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. --- src/NCollection/NCollection_Vec4.hxx | 9 +++ src/OpenGl/OpenGl_Clipping.cxx | 22 +++--- src/OpenGl/OpenGl_Clipping.hxx | 6 ++ src/OpenGl/OpenGl_SetOfShaderPrograms.hxx | 18 ++--- src/OpenGl/OpenGl_ShaderManager.cxx | 67 +++++++++++++++++-- src/OpenGl/OpenGl_ShaderManager.hxx | 15 ++++- src/OpenGl/OpenGl_Structure.cxx | 81 ++++++++++++++++++++--- 7 files changed, 178 insertions(+), 40 deletions(-) diff --git a/src/NCollection/NCollection_Vec4.hxx b/src/NCollection/NCollection_Vec4.hxx index e3016813e6..87948cb8c4 100644 --- a/src/NCollection/NCollection_Vec4.hxx +++ b/src/NCollection/NCollection_Vec4.hxx @@ -316,6 +316,15 @@ public: 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) { diff --git a/src/OpenGl/OpenGl_Clipping.cxx b/src/OpenGl/OpenGl_Clipping.cxx index 25398dc512..4ff37726c4 100755 --- a/src/OpenGl/OpenGl_Clipping.cxx +++ b/src/OpenGl/OpenGl_Clipping.cxx @@ -147,14 +147,14 @@ void OpenGl_Clipping::Remove (const Handle(OpenGl_Context)& theGlCtx, 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) @@ -200,19 +200,15 @@ void OpenGl_Clipping::SetEnabled (const Handle(OpenGl_Context)& theGlCtx, 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 @@ -253,5 +249,5 @@ void OpenGl_Clipping::SetEnabled (const Handle(OpenGl_Context)& theGlCtx, } } - aProps.IsEnabled = theIsEnabled; + aProps->IsEnabled = theIsEnabled; } diff --git a/src/OpenGl/OpenGl_Clipping.hxx b/src/OpenGl/OpenGl_Clipping.hxx index 6588ffa0b9..59da17efff 100755 --- a/src/OpenGl/OpenGl_Clipping.hxx +++ b/src/OpenGl/OpenGl_Clipping.hxx @@ -86,6 +86,12 @@ public: //! @name non-modifying getters 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. diff --git a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx index abf31697e7..c4977b6a68 100644 --- a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx +++ b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx @@ -22,14 +22,16 @@ //! 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 diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index a8f3a2e387..257843cc8e 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -221,7 +221,7 @@ const char THE_FUNC_directionalLightFirst[] = //! 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];" @@ -231,6 +231,24 @@ const char THE_FRAG_CLIP_PLANES[] = 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" }"; + } // ======================================================================= @@ -1048,7 +1066,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad 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;" @@ -1059,7 +1077,19 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad 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; @@ -1325,7 +1355,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S 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;" @@ -1336,7 +1366,19 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S 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); @@ -1446,9 +1488,20 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha 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() diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index f9eaf9ffc9..b13d422818 100644 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -277,10 +277,21 @@ protected: { 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 diff --git a/src/OpenGl/OpenGl_Structure.cxx b/src/OpenGl/OpenGl_Structure.cxx index 767288cdc8..f710c4e26c 100644 --- a/src/OpenGl/OpenGl_Structure.cxx +++ b/src/OpenGl/OpenGl_Structure.cxx @@ -518,13 +518,12 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con // Set up plane equations for non-structure transformed global model-view matrix // List of planes to be applied to context state - NCollection_Handle aUserPlanes; + Handle(NCollection_Shared) 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()) @@ -534,14 +533,12 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con if (aUserPlanes.IsNull()) { - aUserPlanes = new Graphic3d_SequenceOfHClipPlane(); + aUserPlanes = new NCollection_Shared(); } - aUserPlanes->Append (aClipPlane); } } - - if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty()) + if (!aUserPlanes.IsNull()) { // add planes at loaded view matrix state aCtx->ChangeClipping().AddWorld (aCtx, *aUserPlanes); @@ -550,9 +547,61 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con 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(); + 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) @@ -562,13 +611,25 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con // 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);