0027787: Visualization, TKOpenGl - Optimize rendering by additional check whether...
authordbp <dbp@opencascade.com>
Thu, 18 Aug 2016 16:41:05 +0000 (19:41 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 25 Aug 2016 08:17:45 +0000 (11:17 +0300)
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
src/OpenGl/OpenGl_Clipping.cxx
src/OpenGl/OpenGl_Clipping.hxx
src/OpenGl/OpenGl_SetOfShaderPrograms.hxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
src/OpenGl/OpenGl_Structure.cxx

index e301681..87948cb 100644 (file)
@@ -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)
   {
index 25398dc..4ff3772 100755 (executable)
@@ -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;
 }
index 6588ffa..59da17e 100755 (executable)
@@ -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.
index abf3169..c4977b6 100644 (file)
 //! 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
index a8f3a2e..257843c 100644 (file)
@@ -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()
index f9eaf9f..b13d422 100644 (file)
@@ -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
index 767288c..f710c4e 100644 (file)
@@ -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<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())
@@ -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<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);
@@ -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<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)
@@ -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);