]> OCCT Git - occt-copy.git/commitdiff
0027223: Visualization, Ray Tracing - add support of clipping planes CR27223
authorDenis BOGOLEPOV <dbp@dbp.nnov.opencascade.com>
Thu, 3 Mar 2016 10:38:45 +0000 (13:38 +0300)
committerDenis BOGOLEPOV <dbp@dbp.nnov.opencascade.com>
Thu, 3 Mar 2016 10:38:45 +0000 (13:38 +0300)
samples/tcl/pathtrace.tcl
src/Graphic3d/Graphic3d_CStructure.hxx
src/OpenGl/OpenGl_SceneGeometry.cxx
src/OpenGl/OpenGl_SceneGeometry.hxx
src/OpenGl/OpenGl_Structure.cxx
src/OpenGl/OpenGl_Structure.hxx
src/OpenGl/OpenGl_View.hxx
src/OpenGl/OpenGl_View_Raytrace.cxx
src/Shaders/RaytraceBase.fs

index 713295a3709104548bc1f3c22fb4a8b9f1cc748d..874c2d04e4f5140d41b0dffd8e05f5a3a74cc14e 100644 (file)
@@ -75,4 +75,8 @@ vbsdf r -kd 0.5 0.9 0.3 -ks 0.0 -kr 0.3 -n
 vbsdf r -fresnel Constant 1.0
 vsetlocation r 0.5 0.65 0.1
 
+vclipplane create pln
+vclipplane change pln equation 0 0 -1 0.1
+vclipplane set pln object s
+
 vrenderparams -ray -gi -rayDepth 8
index cc2bee362525a8c6b35cb2b2b1e80c0cf727a3c6..4e7c68c36b07b15ff0eda7cfa12ff03fb6254d4a 100644 (file)
@@ -54,7 +54,7 @@ public:
   }
 
   //! Pass clip planes to the associated graphic driver structure
-  void SetClipPlanes (const Graphic3d_SequenceOfHClipPlane& thePlanes) { myClipPlanes = thePlanes; }
+  virtual void SetClipPlanes (const Graphic3d_SequenceOfHClipPlane& thePlanes) { myClipPlanes = thePlanes; }
 
   //! @return bounding box of this presentation
   const Graphic3d_BndBox4f& BoundingBox() const
index cbdb7d035ab89e642e4ad30e34dc4bc3c72056fb..1325a7dac8e47f2ae1c3e7525bde28a2452690b3 100755 (executable)
@@ -520,6 +520,18 @@ Standard_Boolean OpenGl_RaytraceGeometry::UpdateTextureHandles (const Handle(Ope
   return Standard_True;
 }
 
+// =======================================================================
+// function : OpenGl_RaytraceClipPlanes
+// purpose  : Creates new set of clipping planes
+// =======================================================================
+OpenGl_RaytraceClipPlanes::OpenGl_RaytraceClipPlanes()
+{
+  for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < MAX_PLANE_NUMBER; ++aPlaneIdx)
+  {
+    myClipPlanes[aPlaneIdx * 2] = BVH_Vec4f (-1.f, -1.f, -1.f, -1.f);
+  }
+}
+
 namespace OpenGl_Raytrace
 {
   // =======================================================================
index d64bfbf27a1db602cc44b65427135af393b14b50..241d9b8431f22157604ee0b4b179d8e91089af22 100755 (executable)
@@ -223,6 +223,133 @@ private:
 
 };
 
+//! Set of clipping planes specific for OpenGL primitive array.
+class OpenGl_RaytraceClipPlanes
+{
+public:
+
+  //! Maximum number of clipping planes used in ray-tracing for each
+  //! OpenGL primitive array. This is not implementation restriction,
+  //! but it is reasonable to limit max number of planes in order to
+  //! simplify GLSL data representation.
+  static const Standard_Integer MAX_PLANE_NUMBER = 8;
+
+  //! State of clipping plane.
+  enum ClipPlaneState {
+
+    CLIP_PLANE_OFF   = -1,  //!< plane is deactivated
+    CLIP_PLANE_VIEW  =  0,  //!< plane is in view space
+    CLIP_PLANE_WORLD =  1   //!< plane is in world space
+  };
+
+  //! Wrapper for clipping plane configuration.
+  class ClipPlane
+  {
+  public:
+
+    //! Creates new clipping plane wrapper.
+    ClipPlane (BVH_Vec4f& theSettings,
+               BVH_Vec4f& theEquation) : mySettings (theSettings),
+                                         myEquation (theEquation) {}
+
+    //! Sets 4D equation vector for clipping plane.
+    void SetEquation (const BVH_Vec4d& theEquation, const ClipPlaneState theState = CLIP_PLANE_WORLD)
+    {
+      for (Standard_Integer anIndex = 0; anIndex < 4; ++anIndex)
+      {
+        myEquation[anIndex] = static_cast<Standard_ShortReal> (theEquation[anIndex]);
+      }
+
+      SetState (theState);
+    }
+
+    //! Returns state of clipping plane.
+    ClipPlaneState State()
+    {
+      return static_cast<ClipPlaneState> (mySettings.x());
+    }
+
+    //! Sets state of clipping plane.
+    void SetState (const ClipPlaneState theState)
+    {
+      mySettings.x() = static_cast<Standard_ShortReal> (theState);
+    }
+
+  private:
+
+    //! Settings of clipping plane.
+    BVH_Vec4f& mySettings;
+
+    //! 4D equation vector of clipping plane.
+    BVH_Vec4f& myEquation;
+  };
+
+public:
+
+  //! Creates new set of clipping planes.
+  OpenGl_RaytraceClipPlanes();
+
+  //! Returns clipping plane for the given index.
+  ClipPlane operator[] (const Standard_Integer theIndex)
+  {
+    return ClipPlane (myClipPlanes[theIndex * 2 + 0],
+                      myClipPlanes[theIndex * 2 + 1]);
+  }
+
+  //! Returns packed (serialized) representation of clipping planes set.
+  const Standard_ShortReal* Packed()
+  {
+    return reinterpret_cast<Standard_ShortReal*> (this);
+  }
+
+private:
+
+  //! Serialized clipping planes storage.
+  BVH_Vec4f myClipPlanes[MAX_PLANE_NUMBER * 2];
+
+};
+
+//! Stores transform properties of ray-tracing object.
+class OpenGl_RaytraceTransform : public BVH_Transform<Standard_ShortReal, 4>
+{
+public:
+
+  //! Value of invalid clipping plane set.
+  static const Standard_Integer NO_CLIPPING = -1;
+
+public:
+
+  //! Creates new identity transformation.
+  OpenGl_RaytraceTransform() : BVH_Transform<Standard_ShortReal, 4>()
+  {
+    myClipSetID = NO_CLIPPING; // no clipping by default
+  }
+
+  //! Creates new transformation with specified matrix.
+  OpenGl_RaytraceTransform (const BVH_Mat4f& theTransform) : BVH_Transform<Standard_ShortReal, 4> (theTransform)
+  {
+    myClipSetID = NO_CLIPPING; // no clipping by default
+  }
+
+  //! Returns ID of associated set of clipping planes.
+  Standard_Integer ClipSetID() const
+  {
+    return myClipSetID;
+  }
+
+  //! Sets ID of associated set of clipping planes.
+  void SetClipSetID (const Standard_Integer theClipSetID)
+  {
+    myClipSetID = theClipSetID;
+  }
+
+protected:
+
+  //! ID of associated set of clipping planes.
+  Standard_Integer myClipSetID;
+
+};
+
 //! Stores geometry of ray-tracing scene.
 class OpenGl_RaytraceGeometry : public BVH_Geometry<Standard_ShortReal, 3>
 {
@@ -247,6 +374,10 @@ public:
   std::vector<OpenGl_RaytraceMaterial,
     NCollection_StdAllocator<OpenGl_RaytraceMaterial> > Materials;
 
+  //! Array of sets of clipping plane parameters.
+  std::vector<OpenGl_RaytraceClipPlanes,
+    NCollection_StdAllocator<OpenGl_RaytraceClipPlanes> > ClipPlanes;
+
   //! Global ambient from all light sources.
   BVH_Vec4f Ambient;
 
index d5e22fc2b9bf18d1ec7be57591e2ca3bb02a0a08..21c8cb6f6da1600ef8f590afda4803ce12ec2b02 100644 (file)
@@ -241,6 +241,20 @@ void OpenGl_Structure::SetAspectText (const CALL_DEF_CONTEXTTEXT &theAspect)
   myAspectText->SetAspect (theAspect);
 }
 
+// =======================================================================
+// function : SetClipPlanes
+// purpose  :
+// =======================================================================
+void OpenGl_Structure::SetClipPlanes (const Graphic3d_SequenceOfHClipPlane &thePlanes)
+{
+  Graphic3d_CStructure::SetClipPlanes (thePlanes);
+
+  if (IsRaytracable())
+  {
+    ++myModificationState;
+  }
+}
+
 // =======================================================================
 // function : clearHighlightBox
 // purpose  :
index 6a4f2157c5fa849d13921b1b7dd4ce37a74177b2..b9d2812dca5da8673d1b899059fd202e8be0464a 100644 (file)
@@ -129,6 +129,9 @@ public:
 
   Standard_EXPORT void Clear (const Handle(OpenGl_Context)& theGlCtx);
 
+  //! Pass clip planes to the associated graphic driver structure
+  void SetClipPlanes (const Graphic3d_SequenceOfHClipPlane& thePlanes);
+
   //! Renders groups of structure without applying any attributes (i.e. transform, material etc).
   //! @param theWorkspace current workspace
   //! @param theHasClosed flag will be set to TRUE if structure contains at least one group of closed primitives
index 026c583469cf539c2e9eba6609500f6aa0bafae3..0f62cd6b29240cc76b167a7013c8fdc274947986 100644 (file)
@@ -702,12 +702,13 @@ protected: //! @name data types related to ray-tracing
 
     OpenGl_RT_RaytraceMaterialTexture = 9,
     OpenGl_RT_RaytraceLightSrcTexture = 10,
+    OpenGl_RT_RaytraceClippingTexture = 11,
 
-    OpenGl_RT_FsaaInputTexture = 11,
-    OpenGl_RT_PrevAccumTexture = 12,
+    OpenGl_RT_FsaaInputTexture = 12,
+    OpenGl_RT_PrevAccumTexture = 13,
 
-    OpenGl_RT_OpenGlColorTexture = 13,
-    OpenGl_RT_OpenGlDepthTexture = 14
+    OpenGl_RT_OpenGlColorTexture = 14,
+    OpenGl_RT_OpenGlDepthTexture = 15
   };
 
   //! Tool class for management of shader sources.
@@ -1032,6 +1033,8 @@ protected: //! @name fields related to ray-tracing
   Handle(OpenGl_TextureBufferArb) myRaytraceMaterialTexture;
   //! Texture buffer of light source properties.
   Handle(OpenGl_TextureBufferArb) myRaytraceLightSrcTexture;
+  //! Texture buffer of clipping planes parameters.
+  Handle(OpenGl_TextureBufferArb) myRaytraceClippingTexture;
 
   //! 1st framebuffer (FBO) to perform adaptive FSAA.
   Handle(OpenGl_FrameBuffer) myRaytraceFBO1[2];
index 0839951abd6b7f53e7add63dc2414da90dd7fd01..46c52ff5e83eb709c28eae9f190a034313029b03 100644 (file)
@@ -403,7 +403,7 @@ Standard_Boolean OpenGl_View::addRaytraceStructure (const OpenGl_Structure*
     return Standard_True;
   }
 
-  // Get structure material
+  // Get material of the structure
   OpenGl_RaytraceMaterial aStructMaterial;
 
   if (theStructure->AspectFace() != NULL)
@@ -435,6 +435,45 @@ Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure*
                                                  const Graphic3d_Mat4*          theTransform,
                                                  const Handle(OpenGl_Context)&  theGlContext)
 {
+  // ID of clipping plane set
+  Standard_Integer aClipSetID = -1;
+
+  // Collect clipping planes of structure scope
+  if (!theStructure->ClipPlanes().IsEmpty())
+  {
+    NCollection_Handle<Graphic3d_SequenceOfHClipPlane> aUserPlanes;
+
+    for (Graphic3d_SequenceOfHClipPlane::Iterator aClipIter (theStructure->ClipPlanes()); aClipIter.More(); aClipIter.Next())
+    {
+      const Handle(Graphic3d_ClipPlane)& aClipPlane = aClipIter.Value();
+
+      if (aClipPlane->IsOn())
+      {
+        if (aUserPlanes.IsNull())
+        {
+          aUserPlanes = new Graphic3d_SequenceOfHClipPlane();
+        }
+
+        aUserPlanes->Append (aClipPlane);
+      }
+    }
+
+    if (!aUserPlanes.IsNull())
+    {
+      myRaytraceGeometry.ClipPlanes.push_back (OpenGl_RaytraceClipPlanes());
+
+      for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < aUserPlanes->Size(); ++aPlaneIdx)
+      {
+        if (aPlaneIdx < OpenGl_RaytraceClipPlanes::MAX_PLANE_NUMBER)
+        {
+          myRaytraceGeometry.ClipPlanes.back()[aPlaneIdx].SetEquation (aUserPlanes->operator ()(aPlaneIdx + 1)->GetEquation());
+        }
+      }
+
+      aClipSetID = static_cast<Standard_Integer> (myRaytraceGeometry.ClipPlanes.size() - 1);
+    }
+  }
+
   for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next())
   {
     // Get group material
@@ -476,13 +515,18 @@ Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure*
           {
             OpenGl_TriangleSet* aSet = aSetIter->second;
 
-            BVH_Transform<Standard_ShortReal, 4>* aTransform = new BVH_Transform<Standard_ShortReal, 4>();
+            OpenGl_RaytraceTransform* aTransform = new OpenGl_RaytraceTransform;
 
             if (theTransform != NULL)
             {
               aTransform->SetTransform (*theTransform);
             }
 
+            if (aClipSetID != OpenGl_RaytraceTransform::NO_CLIPPING)
+            {
+              aTransform->SetClipSetID (aClipSetID);
+            }
+
             aSet->SetProperties (aTransform);
 
             if (aSet->MaterialIndex() != OpenGl_TriangleSet::INVALID_MATERIAL && aSet->MaterialIndex() != aMatID)
@@ -492,18 +536,22 @@ Standard_Boolean OpenGl_View::addRaytraceGroups (const OpenGl_Structure*
           }
           else
           {
-            NCollection_Handle<BVH_Object<Standard_ShortReal, 3> > aSet =
-              addRaytracePrimitiveArray (aPrimArray, aMatID, 0);
+            NCollection_Handle<BVH_Object<Standard_ShortReal, 3> > aSet = addRaytracePrimitiveArray (aPrimArray, aMatID, 0);
 
             if (!aSet.IsNull())
             {
-              BVH_Transform<Standard_ShortReal, 4>* aTransform = new BVH_Transform<Standard_ShortReal, 4>;
+              OpenGl_RaytraceTransform* aTransform = new OpenGl_RaytraceTransform;
 
               if (theTransform != NULL)
               {
                 aTransform->SetTransform (*theTransform);
               }
 
+              if (aClipSetID != OpenGl_RaytraceTransform::NO_CLIPPING)
+              {
+                aTransform->SetClipSetID (aClipSetID);
+              }
+
               aSet->SetProperties (aTransform);
 
               myRaytraceGeometry.Objects().Append (aSet);
@@ -1478,6 +1526,8 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Handle(OpenGl_Context
         "uRaytraceMaterialTexture", OpenGl_RT_RaytraceMaterialTexture);
       aShaderProgram->SetSampler (theGlContext,
         "uRaytraceLightSrcTexture", OpenGl_RT_RaytraceLightSrcTexture);
+      aShaderProgram->SetSampler (theGlContext,
+        "uRaytraceClippingTexture", OpenGl_RT_RaytraceClippingTexture);
 
       aShaderProgram->SetSampler (theGlContext,
         "uOpenGlColorTexture", OpenGl_RT_OpenGlColorTexture);
@@ -1629,6 +1679,7 @@ void OpenGl_View::releaseRaytraceResources (const Handle(OpenGl_Context)& theGlC
 
   nullifyResource (theGlContext, myRaytraceLightSrcTexture);
   nullifyResource (theGlContext, myRaytraceMaterialTexture);
+  nullifyResource (theGlContext, myRaytraceClippingTexture);
 
   myRaytraceGeometry.ReleaseResources (theGlContext);
 
@@ -1760,7 +1811,7 @@ Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)&
   }
 
   /////////////////////////////////////////////////////////////////////////////
-  // Create OpenGL BVH buffers
+  // Create BVH buffers
 
   if (mySceneNodeInfoTexture.IsNull())  // create scene BVH buffers
   {
@@ -1800,6 +1851,9 @@ Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)&
     }
   }
 
+  /////////////////////////////////////////////////////////////////////////////
+  // Create material buffer
+
   if (myRaytraceMaterialTexture.IsNull()) // create material buffer
   {
     myRaytraceMaterialTexture = new OpenGl_TextureBufferArb;
@@ -1807,7 +1861,23 @@ Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)&
     if (!myRaytraceMaterialTexture->Create (theGlContext))
     {
 #ifdef RAY_TRACE_PRINT_INFO
-      std::cout << "Error: Failed to create buffers for material data" << std::endl;
+      std::cout << "Error: Failed to create buffer for material data" << std::endl;
+#endif
+      return Standard_False;
+    }
+  }
+
+  /////////////////////////////////////////////////////////////////////////////
+  // Create clip planes buffer
+
+  if (myRaytraceClippingTexture.IsNull()) // create clipping planes buffer
+  {
+    myRaytraceClippingTexture = new OpenGl_TextureBufferArb;
+
+    if (!myRaytraceClippingTexture->Create (theGlContext))
+    {
+#ifdef RAY_TRACE_PRINT_INFO
+      std::cout << "Error: Failed to create buffer for clip plane data" << std::endl;
 #endif
       return Standard_False;
     }
@@ -1825,13 +1895,17 @@ Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)&
     OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
       myRaytraceGeometry.Objects().ChangeValue (anElemIndex).operator->());
 
-    const BVH_Transform<Standard_ShortReal, 4>* aTransform = 
-      dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (aTriangleSet->Properties().operator->());
+    const OpenGl_RaytraceTransform* aTransform =
+      dynamic_cast<const OpenGl_RaytraceTransform*> (aTriangleSet->Properties().operator->());
 
     Standard_ASSERT_RETURN (aTransform != NULL,
       "OpenGl_TriangleSet does not contain transform", Standard_False);
 
     aNodeTransforms[anElemIndex] = aTransform->Inversed();
+
+    // Note: write clip plane ID in last matrix component, because
+    // the last matrix row is not used for transformation purposes
+    aNodeTransforms[anElemIndex].SetValue (3, 3, aTransform->ClipSetID());
   }
 
   aResult &= mySceneTransformTexture->Init (theGlContext, 4,
@@ -2006,6 +2080,23 @@ Standard_Boolean OpenGl_View::uploadRaytraceData (const Handle(OpenGl_Context)&
     }
   }
 
+  /////////////////////////////////////////////////////////////////////////////
+  // Write clip planes buffer
+
+  if (myRaytraceGeometry.ClipPlanes.size() != 0)
+  {
+    aResult &= myRaytraceClippingTexture->Init (theGlContext, 4,
+      GLsizei (myRaytraceGeometry.ClipPlanes.size() * 16), myRaytraceGeometry.ClipPlanes.front().Packed());
+
+    if (!aResult)
+    {
+#ifdef RAY_TRACE_PRINT_INFO
+      std::cout << "Error: Failed to upload clipping planes buffer" << std::endl;
+#endif
+      return Standard_False;
+    }
+  }
+
   myIsRaytraceDataValid = myRaytraceGeometry.Objects().Size() != 0;
 
 #ifdef RAY_TRACE_PRINT_INFO
@@ -2294,6 +2385,7 @@ void OpenGl_View::bindRaytraceTextures (const Handle(OpenGl_Context)& theGlConte
   mySceneTransformTexture->BindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture);
   myRaytraceMaterialTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture);
   myRaytraceLightSrcTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture);
+  myRaytraceClippingTexture->BindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceClippingTexture);
 
   if (!myOpenGlFBO.IsNull())
   {
@@ -2318,6 +2410,7 @@ void OpenGl_View::unbindRaytraceTextures (const Handle(OpenGl_Context)& theGlCon
   mySceneTransformTexture->UnbindTexture   (theGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture);
   myRaytraceMaterialTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture);
   myRaytraceLightSrcTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture);
+  myRaytraceClippingTexture->UnbindTexture (theGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceClippingTexture);
 
   if (!myOpenGlFBO.IsNull())
   {
index 13f17b26d4bbfbbd917f8d38f8d2bd1d05385ec5..5676879fc7b1ca93c3b8f5f0f8a8c8b371e2fa8b 100644 (file)
@@ -60,6 +60,9 @@ uniform isamplerBuffer uGeometryTriangTexture;
 uniform samplerBuffer uRaytraceMaterialTexture;
 //! Texture buffer of light source properties.
 uniform samplerBuffer uRaytraceLightSrcTexture;
+//! Texture buffer of clipping planes properties.
+uniform samplerBuffer uRaytraceClippingTexture;
+
 //! Environment map texture.
 uniform sampler2D uEnvironmentMapTexture;
 
@@ -375,12 +378,20 @@ struct SSubTree
   ivec4 SubData;
 };
 
+#define EMPTY_ROOT ivec4(0)
+
 #define TRS_OFFSET(treelet) treelet.SubData.x
 #define BVH_OFFSET(treelet) treelet.SubData.y
 #define VRT_OFFSET(treelet) treelet.SubData.z
 #define TRG_OFFSET(treelet) treelet.SubData.w
 
-#define EMPTY_ROOT ivec4(0)
+#define MAX_CLIP_PLANES 1
+
+#define IS_PLANE_ACTIVE(params) (params.x != -1.F)
+#define IS_PLANE_HIDDEN(params) (params.x == -1.F)
+
+#define PLANE_SETTINGS(trsf, index) (16 * int(trsf.w) + 2 * index + 0)
+#define PLANE_EQUATION(trsf, index) (16 * int(trsf.w) + 2 * index + 1)
 
 // =======================================================================
 // function : SceneNearestHit
@@ -396,6 +407,9 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
 
   SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
 
+  float aClipMax =  MAXFLOAT;
+  float aClipMin = -MAXFLOAT;
+
   for (bool toContinue = true; toContinue;)
   {
     ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
@@ -472,7 +486,7 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
         float aTime = IntersectTriangle (aSubTree.TrsfRay,
           aPoint0, aPoint1, aPoint2, aParams, aNormal);
 
-        if (aTime < theHit.Time)
+        if (aTime > aClipMin && aTime < aClipMax && aTime < theHit.Time)
         {
           aTriIndex = aTriangle;
 
@@ -493,13 +507,34 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
     }
     else if (aData.x > 0) // switch node
     {
-      aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
+      aClipMax =  MAXFLOAT;
+      aClipMin = -MAXFLOAT;
+
+      aSubTree.SubData = ivec4 (aData.x * 4 - 4, aData.yzw); // store BVH sub-root
 
       vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
       vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1);
       vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
       vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
 
+      for (int aPlaneIdx = 0; aInvTransf3.w >= 0.0 && aPlaneIdx < MAX_CLIP_PLANES; ++aPlaneIdx)
+      {
+        vec4 aSettings = texelFetch (uRaytraceClippingTexture, PLANE_SETTINGS (aInvTransf3, aPlaneIdx));
+        vec4 aEquation = texelFetch (uRaytraceClippingTexture, PLANE_EQUATION (aInvTransf3, aPlaneIdx));
+
+        float aNdotD = -dot (aEquation.xyz, theRay.Direct);
+
+        if (IS_PLANE_ACTIVE (aSettings))
+        {
+          float aPlaneTime = (dot (aEquation.xyz, theRay.Origin) + aEquation.w) / aNdotD;
+
+          if (aNdotD < 0.0)
+            aClipMin = max (aClipMin, aPlaneTime);
+          else
+            aClipMax = min (aClipMax, aPlaneTime);
+        }
+      }
+
       aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
                                                       aInvTransf0,
                                                       aInvTransf1,
@@ -537,6 +572,9 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
 
   SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
 
+  float aClipMax =  MAXFLOAT;
+  float aClipMin = -MAXFLOAT;
+
   for (bool toContinue = true; toContinue;)
   {
     ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
@@ -614,12 +652,12 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
           aPoint0, aPoint1, aPoint2, aParams, aNormal);
 
 #ifdef TRANSPARENT_SHADOWS
-        if (aTime < theDistance)
+        if (aTime > aClipMin && aTime < aClipMax && aTime < theDistance)
         {
           aFactor *= 1.f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
         }
 #else
-        if (aTime < theDistance)
+        if (aTime > aClipMin && aTime < aClipMax && aTime < theDistance)
         {
           aFactor = 0.f;
         }
@@ -637,6 +675,9 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
     }
     else if (aData.x > 0) // switch node
     {
+      aClipMax =  MAXFLOAT;
+      aClipMin = -MAXFLOAT;
+
       aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
 
       vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
@@ -644,6 +685,24 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
       vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
       vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
 
+      for (int aPlaneIdx = 0; aInvTransf3.w >= 0.0 && aPlaneIdx < MAX_CLIP_PLANES; ++aPlaneIdx)
+      {
+        vec4 aSettings = texelFetch (uRaytraceClippingTexture, PLANE_SETTINGS (aInvTransf3, aPlaneIdx));
+        vec4 aEquation = texelFetch (uRaytraceClippingTexture, PLANE_EQUATION (aInvTransf3, aPlaneIdx));
+
+        float aNdotD = -dot (aEquation.xyz, theRay.Direct);
+
+        if (IS_PLANE_ACTIVE (aSettings))
+        {
+          float aPlaneTime = (dot (aEquation.xyz, theRay.Origin) + aEquation.w) / aNdotD;
+
+          if (aNdotD < 0.0)
+            aClipMin = max (aClipMin, aPlaneTime);
+          else
+            aClipMax = min (aClipMax, aPlaneTime);
+        }
+      }
+
       aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
                                                       aInvTransf0,
                                                       aInvTransf1,