0024739: TKOpenGl - port ray-tracing from OpenCL to GLSL for better integration and...
[occt.git] / src / OpenGl / OpenGl_SceneGeometry.cxx
old mode 100644 (file)
new mode 100755 (executable)
index be2f350..73ecc43
@@ -2,46 +2,44 @@
 // Created by: Denis BOGOLEPOV
 // Copyright (c) 2013 OPEN CASCADE SAS
 //
-// The content of this file is subject to the Open CASCADE Technology Public
-// License Version 6.5 (the "License"). You may not use the content of this file
-// except in compliance with the License. Please obtain a copy of the License
-// at http://www.opencascade.org and read it completely before using this file.
+// This file is part of Open CASCADE Technology software library.
 //
-// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
-// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
 //
-// The Original Code and all software distributed under the License is
-// distributed on an "AS IS" basis, without warranty of any kind, and the
-// Initial Developer hereby disclaims all such warranties, including without
-// limitation, any warranties of merchantability, fitness for a particular
-// purpose or non-infringement. Please see the License for the specific terms
-// and conditions governing the rights and limitations under the License.
-
-#ifdef HAVE_CONFIG_H
-  #include <config.h>
-#endif
-
-#ifdef HAVE_OPENCL
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
 
-#include <limits>
+#include <Standard_Assert.hxx>
 
-#include <OpenGl_SceneGeometry.hxx>
+#ifdef HAVE_TBB
+  // On Windows, function TryEnterCriticalSection has appeared in Windows NT
+  // and is surrounded by #ifdef in MS VC++ 7.1 headers.
+  // Thus to use it we need to define appropriate macro saying that we wil
+  // run on Windows NT 4.0 at least
+  #if ((defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN32_WINNT))
+    #define _WIN32_WINNT 0x0501
+  #endif
 
-namespace
-{
+  #include <tbb/tbb.h>
+#endif
 
-  //! Number of node bins per axis.
-  static const int THE_NUMBER_OF_BINS = 32;
+#include <OpenGl_SceneGeometry.hxx>
 
-  //! Max number of triangles per leaf node.
-  static const int THE_MAX_LEAF_TRIANGLES = 4;
+//! Use this macro to output BVH profiling info
+//#define BVH_PRINT_INFO
 
-  //! Useful constant for null integer 4D vector.
-  static const OpenGl_RTVec4i THE_ZERO_VEC_4I;
+#ifdef BVH_PRINT_INFO
+  #include <OSD_Timer.hxx>
+#endif
 
+namespace
+{
   //! Useful constant for null floating-point 4D vector.
-  static const OpenGl_RTVec4f THE_ZERO_VEC_4F;
-
+  static const BVH_Vec4f ZERO_VEC_4F;
 };
 
 // =======================================================================
@@ -49,29 +47,29 @@ namespace
 // purpose  : Creates new default material
 // =======================================================================
 OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial()
-: Ambient      (THE_ZERO_VEC_4F),
-  Diffuse      (THE_ZERO_VEC_4F),
-  Specular     (THE_ZERO_VEC_4F),
-  Emission     (THE_ZERO_VEC_4F),
-  Reflection   (THE_ZERO_VEC_4F),
-  Refraction   (THE_ZERO_VEC_4F),
-  Transparency (THE_ZERO_VEC_4F)
+: Ambient      (ZERO_VEC_4F),
+  Diffuse      (ZERO_VEC_4F),
+  Specular     (ZERO_VEC_4F),
+  Emission     (ZERO_VEC_4F),
+  Reflection   (ZERO_VEC_4F),
+  Refraction   (ZERO_VEC_4F),
+  Transparency (ZERO_VEC_4F)
 { }
 
 // =======================================================================
 // function : OpenGl_RaytraceMaterial
 // purpose  : Creates new material with specified properties
 // =======================================================================
-OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const OpenGl_RTVec4f& theAmbient,
-                                                  const OpenGl_RTVec4f& theDiffuse,
-                                                  const OpenGl_RTVec4f& theSpecular)
+OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
+                                                  const BVH_Vec4f& theDiffuse,
+                                                  const BVH_Vec4f& theSpecular)
 : Ambient      (theAmbient),
   Diffuse      (theDiffuse),
   Specular     (theSpecular),
-  Emission     (THE_ZERO_VEC_4F),
-  Reflection   (THE_ZERO_VEC_4F),
-  Refraction   (THE_ZERO_VEC_4F),
-  Transparency (THE_ZERO_VEC_4F)
+  Emission     (ZERO_VEC_4F),
+  Reflection   (ZERO_VEC_4F),
+  Refraction   (ZERO_VEC_4F),
+  Transparency (ZERO_VEC_4F)
 {
   //
 }
@@ -80,17 +78,17 @@ OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const OpenGl_RTVec4f& theAmbie
 // function : OpenGl_RaytraceMaterial
 // purpose  : Creates new material with specified properties
 // =======================================================================
-OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const OpenGl_RTVec4f& theAmbient,
-                                                  const OpenGl_RTVec4f& theDiffuse,
-                                                  const OpenGl_RTVec4f& theSpecular,
-                                                  const OpenGl_RTVec4f& theEmission,
-                                                  const OpenGl_RTVec4f& theTranspar)
+OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
+                                                  const BVH_Vec4f& theDiffuse,
+                                                  const BVH_Vec4f& theSpecular,
+                                                  const BVH_Vec4f& theEmission,
+                                                  const BVH_Vec4f& theTranspar)
 : Ambient      (theAmbient),
   Diffuse      (theDiffuse),
   Specular     (theSpecular),
   Emission     (theEmission),
-  Reflection   (THE_ZERO_VEC_4F),
-  Refraction   (THE_ZERO_VEC_4F),
+  Reflection   (ZERO_VEC_4F),
+  Refraction   (ZERO_VEC_4F),
   Transparency (theTranspar)
 {
   //
@@ -100,13 +98,13 @@ OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const OpenGl_RTVec4f& theAmbie
 // function : OpenGl_RaytraceMaterial
 // purpose  : Creates new material with specified properties
 // =======================================================================
-OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const OpenGl_RTVec4f& theAmbient,
-                                                  const OpenGl_RTVec4f& theDiffuse,
-                                                  const OpenGl_RTVec4f& theSpecular,
-                                                  const OpenGl_RTVec4f& theEmission,
-                                                  const OpenGl_RTVec4f& theTranspar,
-                                                  const OpenGl_RTVec4f& theReflection,
-                                                  const OpenGl_RTVec4f& theRefraction)
+OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const BVH_Vec4f& theAmbient,
+                                                  const BVH_Vec4f& theDiffuse,
+                                                  const BVH_Vec4f& theSpecular,
+                                                  const BVH_Vec4f& theEmission,
+                                                  const BVH_Vec4f& theTranspar,
+                                                  const BVH_Vec4f& theReflection,
+                                                  const BVH_Vec4f& theRefraction)
 : Ambient      (theAmbient),
   Diffuse      (theDiffuse),
   Specular     (theSpecular),
@@ -122,587 +120,220 @@ OpenGl_RaytraceMaterial::OpenGl_RaytraceMaterial (const OpenGl_RTVec4f& theAmbie
 // function : OpenGl_LightSource
 // purpose  : Creates new light source
 // =======================================================================
-OpenGl_RaytraceLight::OpenGl_RaytraceLight (const OpenGl_RTVec4f& theAmbient)
-: Ambient (theAmbient)
-{
-  //
-}
-
-// =======================================================================
-// function : OpenGl_LightSource
-// purpose  : Creates new light source
-// =======================================================================
-OpenGl_RaytraceLight::OpenGl_RaytraceLight (const OpenGl_RTVec4f& theDiffuse,
-                                            const OpenGl_RTVec4f& thePosition)
+OpenGl_RaytraceLight::OpenGl_RaytraceLight (const BVH_Vec4f& theDiffuse,
+                                            const BVH_Vec4f& thePosition)
 : Diffuse (theDiffuse),
   Position (thePosition)
 {
   //
 }
 
-// =======================================================================
-// function : Center
-// purpose  : Returns centroid of specified triangle
-// =======================================================================
-OpenGl_RTVec4f OpenGl_RaytraceScene::Center (const int theTriangle) const
-{
-  const OpenGl_RTVec4i& anIndex = Triangles [theTriangle];
-
-  return ( Vertices[anIndex.x()] +
-           Vertices[anIndex.y()] +
-           Vertices[anIndex.z()] ) * ( 1.f / 3.f );
-}
-
-// =======================================================================
-// function : CenterAxis
-// purpose  : Returns centroid of specified triangle
-// =======================================================================
-float OpenGl_RaytraceScene::CenterAxis (const int theTriangle,
-                                        const int theAxis) const
-{
-  const OpenGl_RTVec4i& anIndex = Triangles [theTriangle];
-
-  return ( Vertices[anIndex.x()][theAxis] +
-           Vertices[anIndex.y()][theAxis] +
-           Vertices[anIndex.z()][theAxis] ) * ( 1.f / 3.f );
-}
-
-// =======================================================================
-// function : Box
-// purpose  : Returns AABB of specified triangle
-// =======================================================================
-OpenGl_AABB OpenGl_RaytraceScene::Box (const int theTriangle) const
-{
-  const OpenGl_RTVec4i& anIndex = Triangles[theTriangle];
-
-  const OpenGl_RTVec4f& pA = Vertices[anIndex.x()];
-  const OpenGl_RTVec4f& pB = Vertices[anIndex.y()];
-  const OpenGl_RTVec4f& pC = Vertices[anIndex.z()];
-
-  OpenGl_AABB aBox (pA);
-
-  aBox.Add (pB);
-  aBox.Add (pC);
-
-  return aBox;
-}
-
 // =======================================================================
 // function : Clear
-// purpose  : Clears all scene geometry data
+// purpose  : Clears ray-tracing geometry
 // =======================================================================
-void OpenGl_RaytraceScene::Clear()
+void OpenGl_RaytraceGeometry::Clear()
 {
-  AABB.Clear();
-
-  OpenGl_RTArray4f anEmptyNormals;
-  Normals.swap (anEmptyNormals);
+  BVH_Geometry<Standard_ShortReal, 4>::BVH_Geometry::Clear();
 
-  OpenGl_RTArray4f anEmptyVertices;
-  Vertices.swap (anEmptyVertices);
+  std::vector<OpenGl_RaytraceLight,
+    NCollection_StdAllocator<OpenGl_RaytraceLight> > anEmptySources;
 
-  OpenGl_RTArray4i anEmptyTriangles;
-  Triangles.swap (anEmptyTriangles);
+  Sources.swap (anEmptySources);
 
   std::vector<OpenGl_RaytraceMaterial,
-              NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
+    NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
 
   Materials.swap (anEmptyMaterials);
 }
 
-// =======================================================================
-// function : OpenGl_Node
-// purpose  : Creates new empty BVH node
-// =======================================================================
-OpenGl_BVHNode::OpenGl_BVHNode()
-: myMinPoint (THE_ZERO_VEC_4F),
-  myMaxPoint (THE_ZERO_VEC_4F),
-  myDataRcrd (THE_ZERO_VEC_4I)
-{
-  //
-}
-
-// =======================================================================
-// function : OpenGl_Node
-// purpose  : Creates new BVH node with specified data
-// =======================================================================
-OpenGl_BVHNode::OpenGl_BVHNode (const OpenGl_RTVec4f& theMinPoint,
-                                const OpenGl_RTVec4f& theMaxPoint,
-                                const OpenGl_RTVec4i& theDataRcrd)
-: myMinPoint (theMinPoint),
-  myMaxPoint (theMaxPoint),
-  myDataRcrd (theDataRcrd)
-{
-  //
-}
-
-// =======================================================================
-// function : OpenGl_Node
-// purpose  : Creates new leaf BVH node with specified data
-// =======================================================================
-OpenGl_BVHNode::OpenGl_BVHNode (const OpenGl_AABB& theAABB,
-                                const int          theBegTriangle,
-                                const int          theEndTriangle)
-: myMinPoint (theAABB.CornerMin()),
-  myMaxPoint (theAABB.CornerMax()),
-  myDataRcrd (1,
-              theBegTriangle,
-              theEndTriangle,
-              0)
-{
-  //
-}
-
-// =======================================================================
-// function : OpenGl_Node
-// purpose  : Creates new leaf BVH node with specified data
-// =======================================================================
-OpenGl_BVHNode::OpenGl_BVHNode (const OpenGl_RTVec4f& theMinPoint,
-                                const OpenGl_RTVec4f& theMaxPoint,
-                                const int             theBegTriangle,
-                                const int             theEndTriangle)
-: myMinPoint (theMinPoint),
-  myMaxPoint (theMaxPoint),
-  myDataRcrd (1,
-              theBegTriangle,
-              theEndTriangle,
-              0)
-{
-  //
-}
+#ifdef HAVE_TBB
 
-// =======================================================================
-// function : CleanUp
-// purpose  : Removes all tree nodes
-// =======================================================================
-void OpenGl_BVH::CleanUp()
+struct OpenGL_BVHParallelBuilder
 {
-  OpenGl_RTArray4f anEmptyMinPointBuffer;
-  myMinPointBuffer.swap (anEmptyMinPointBuffer);
-
-  OpenGl_RTArray4f anEmptyMaxPointBuffer;
-  myMaxPointBuffer.swap (anEmptyMaxPointBuffer);
-
-  OpenGl_RTArray4i anEmptyDataRcrdBuffer;
-  myDataRcrdBuffer.swap (anEmptyDataRcrdBuffer);
-}
+  BVH_ObjectSet<Standard_ShortReal, 4>* Set;
 
-// =======================================================================
-// function : Node
-// purpose  : Returns node with specified index
-// =======================================================================
-OpenGl_BVHNode OpenGl_BVH::Node (const int theIndex) const
-{
-  return OpenGl_BVHNode (myMinPointBuffer[theIndex],
-                         myMaxPointBuffer[theIndex],
-                         myDataRcrdBuffer[theIndex]);
-}
-
-// =======================================================================
-// function : SetNode
-// purpose  : Replaces node with specified index
-// =======================================================================
-void OpenGl_BVH::SetNode (const int             theIndex,
-                          const OpenGl_BVHNode& theNode)
-{
-  if (theIndex < static_cast<int> (myMinPointBuffer.size()))
+  OpenGL_BVHParallelBuilder (BVH_ObjectSet<Standard_ShortReal, 4>* theSet)
+    : Set (theSet)
   {
-    myMinPointBuffer[theIndex] = theNode.myMinPoint;
-    myMaxPointBuffer[theIndex] = theNode.myMaxPoint;
-    myDataRcrdBuffer[theIndex] = theNode.myDataRcrd;
+    //
   }
-}
-
-// =======================================================================
-// function : PushNode
-// purpose  : Adds new node to the tree
-// =======================================================================
-int OpenGl_BVH::PushNode (const OpenGl_BVHNode& theNode)
-{
-  myMinPointBuffer.push_back (theNode.myMinPoint);
-  myMaxPointBuffer.push_back (theNode.myMaxPoint);
-  myDataRcrdBuffer.push_back (theNode.myDataRcrd);
-  return static_cast<int> (myDataRcrdBuffer.size() - 1);
-}
 
-// =======================================================================
-// function : OpenGl_NodeBuildTask
-// purpose  : Creates new node building task
-// =======================================================================
-OpenGl_BVHNodeTask::OpenGl_BVHNodeTask()
-: NodeToBuild (0),
-  BegTriangle (0),
-  EndTriangle (0)
-{
-  //
-}
-
-// =======================================================================
-// function : OpenGl_NodeBuildTask
-// purpose  : Creates new node building task
-// =======================================================================
-OpenGl_BVHNodeTask::OpenGl_BVHNodeTask (const int theNodeToBuild,
-                                        const int theBegTriangle,
-                                        const int theEndTriangle)
-: NodeToBuild (theNodeToBuild),
-  BegTriangle (theBegTriangle),
-  EndTriangle (theEndTriangle)
-{
-  //
-}
-
-// =======================================================================
-// function : OpenGl_BinnedBVHBuilder
-// purpose  : Creates new binned BVH builder
-// =======================================================================
-OpenGl_BinnedBVHBuilder::OpenGl_BinnedBVHBuilder()
-: myMaxDepth (30)
-{
-  //
-}
-
-// =======================================================================
-// function : ~OpenGl_BinnedBVHBuilder
-// purpose  : Releases binned BVH builder
-// =======================================================================
-OpenGl_BinnedBVHBuilder::~OpenGl_BinnedBVHBuilder()
-{
-  //
-}
+  void operator() (const tbb::blocked_range<size_t>& theRange) const
+  {
+    for (size_t anObjectIdx = theRange.begin(); anObjectIdx != theRange.end(); ++anObjectIdx)
+    {
+      OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
+        Set->Objects().ChangeValue (static_cast<Standard_Integer> (anObjectIdx)).operator->());
 
-#define BVH_DEBUG_OUTPUT_
+      if (aTriangleSet != NULL)
+      {
+        aTriangleSet->BVH();
+      }
+    }
+  }
+};
 
-#if defined( BVH_DEBUG_OUTPUT )
-  #include <iostream>
 #endif
 
 // =======================================================================
-// function : ReinterpretIntAsFloat
-// purpose  : Reinterprets bits of integer value as floating-point value
-// =======================================================================
-inline float ReinterpretIntAsFloat (int theValue)
-{
-  return *reinterpret_cast< float* > (&theValue);
-}
-
-// =======================================================================
-// function : Build
-// purpose  : Builds BVH tree using binned SAH algorithm
+// function : ProcessAcceleration
+// purpose  : Performs post-processing of high-level BVH
 // =======================================================================
-void OpenGl_BinnedBVHBuilder::Build (OpenGl_RaytraceScene& theGeometry,
-                                     const float           theEpsilon)
+Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
 {
-  CleanUp();
+#ifdef BVH_PRINT_INFO
+    OSD_Timer aTimer;
+#endif
 
-#ifdef BVH_DEBUG_OUTPUT
-  std::cout << "Start building BVH..." << std::endl;
+  MarkDirty(); // force BVH rebuilding
 
-  std::cout << "Triangles: " << theGeometry.Triangles.size() << std::endl;
+#ifdef BVH_PRINT_INFO
+  aTimer.Reset();
+  aTimer.Start();
 #endif
 
-  if (theGeometry.Triangles.size() == 0)
-    return;
-
-  // Create root node with all scene triangles
-  OpenGl_AABB anAABB = theGeometry.AABB;
-  anAABB.CornerMin() = OpenGl_RTVec4f (anAABB.CornerMin().x() - theEpsilon,
-                                       anAABB.CornerMin().y() - theEpsilon,
-                                       anAABB.CornerMin().z() - theEpsilon,
-                                       1.0f);
-  anAABB.CornerMax() = OpenGl_RTVec4f (anAABB.CornerMax().x() + theEpsilon,
-                                       anAABB.CornerMax().y() + theEpsilon,
-                                       anAABB.CornerMax().z() + theEpsilon,
-                                       1.0f);
-  myTree.PushNode (OpenGl_BVHNode (anAABB, 0, static_cast<int> (theGeometry.Triangles.size() - 1)));
-
-#ifdef BVH_DEBUG_OUTPUT
-  std::cout << "Push root node: [" << 0 << ", " <<
-                      theGeometry.Triangles.size() - 1 << "]" << std::endl;
+#ifdef HAVE_TBB
+  // If Intel TBB is available, perform the preliminary
+  // construction of bottom-level scene BVHs
+  tbb::parallel_for (tbb::blocked_range<size_t> (0, Size()),
+    OpenGL_BVHParallelBuilder (this));
 #endif
 
-  // Setup splitting task for the root node
-  myNodeTasksQueue.push_back (OpenGl_BVHNodeTask (0, 0, static_cast<int> (theGeometry.Triangles.size() - 1)));
+  myBottomLevelTreeDepth = 0;
 
-  // Building nodes while tasks queue is not empty
-  for (int aTaskId = 0; aTaskId < static_cast<int> (myNodeTasksQueue.size()); ++aTaskId)
+  for (Standard_Integer anObjectIdx = 0; anObjectIdx < Size(); ++anObjectIdx)
   {
-    BuildNode (theGeometry, aTaskId);
-  }
+    OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
+      myObjects.ChangeValue (anObjectIdx).operator->());
 
-  // Write support data to optimize traverse
-  for (int aNode = 0; aNode < static_cast<int> (myTree.DataRcrdBuffer().size()); ++aNode)
-  {
-    OpenGl_RTVec4i aData = myTree.DataRcrdBuffer()[aNode];
-    myTree.MinPointBuffer()[aNode].w() = ReinterpretIntAsFloat (aData[0] ? aData[1] : -aData[1]);
-    myTree.MaxPointBuffer()[aNode].w() = ReinterpretIntAsFloat (aData[0] ? aData[2] : -aData[2]);
-  }
-}
+    Standard_ASSERT_RETURN (aTriangleSet != NULL,
+      "Error! Failed to get triangulation of OpenGL element", Standard_False);
 
-// =======================================================================
-// function : CleanUp
-// purpose  : Clears previously built tree
-// =======================================================================
-void OpenGl_BinnedBVHBuilder::CleanUp()
-{
-  myTree.CleanUp();
-  myNodeTasksQueue.clear();
-}
+    Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
+      "Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
 
-// =======================================================================
-// function : SetMaxDepth
-// purpose  : Sets maximum tree depth
-// =======================================================================
-void OpenGl_BinnedBVHBuilder::SetMaxDepth (const int theMaxDepth)
-{
-  if (theMaxDepth > 1 && theMaxDepth < 30)
-  {
-    myMaxDepth = theMaxDepth - 1;
+    myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
   }
-}
 
-//! Minimum node size to split.
-static const float THE_NODE_MIN_SIZE = 1e-4f;
+#ifdef BVH_PRINT_INFO
+  aTimer.Stop();
 
-// =======================================================================
-// function : BuildNode
-// purpose  : Builds node using task info
-// =======================================================================
-void OpenGl_BinnedBVHBuilder::BuildNode (OpenGl_RaytraceScene& theGeometry,
-                                         const int             theTask)
-{
-  OpenGl_BVHNodeTask aTask = myNodeTasksQueue[theTask];
-  OpenGl_BVHNode     aNode = myTree.Node (aTask.NodeToBuild);
+  std::cout << "Updating bottom-level BVHs (sec): " <<
+    aTimer.ElapsedTime() << std::endl;
+#endif
 
-#ifdef BVH_DEBUG_OUTPUT
-  std::cout << "Build node " << aTask.NodeToBuild << ": [" <<
-                  aTask.BegTriangle << ", " << aTask.EndTriangle << "]" << std::endl;
+#ifdef BVH_PRINT_INFO
+  aTimer.Reset();
+  aTimer.Start();
 #endif
 
-  OpenGl_AABB anAABB (aNode.MinPoint(), aNode.MaxPoint());
-  const OpenGl_RTVec4f aNodeSize = anAABB.Size();
-  const float aNodeArea = anAABB.Area();
+  NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> > aBVH = BVH();
 
-  // Parameters for storing best split
-  float aMinSplitCost = std::numeric_limits<float>::max();
+#ifdef BVH_PRINT_INFO
+  aTimer.Stop();
 
-  int aMinSplitAxis     = -1;
-  int aMinSplitIndex    =  0;
-  int aMinSplitLftCount =  0;
-  int aMinSplitRghCount =  0;
+  std::cout << "Updating high-level BVH (sec): " <<
+    aTimer.ElapsedTime() << std::endl;
+#endif
+
+  Standard_ASSERT_RETURN (!aBVH.IsNull(),
+    "Error! Failed to update high-level BVH of ray-tracing scene", Standard_False);
+
+  myHighLevelTreeDepth = aBVH->Depth();
 
-  OpenGl_AABB aMinSplitLftAABB;
-  OpenGl_AABB aMinSplitRghAABB;
+  Standard_Integer aVerticesOffset = 0;
+  Standard_Integer aElementsOffset = 0;
+  Standard_Integer aBVHNodesOffset = 0;
 
-  // Find best split
-  for (int anAxis = 0; anAxis < 3; ++anAxis)
+  for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
   {
-    if (aNodeSize[anAxis] <= THE_NODE_MIN_SIZE)
+    if (!aBVH->IsOuter (aNodeIdx))
       continue;
 
-    OpenGl_BinVector aBins (THE_NUMBER_OF_BINS);
-    GetSubVolumes (theGeometry, aNode, aBins, anAxis);
+    Standard_ASSERT_RETURN (aBVH->BegPrimitive (aNodeIdx) == aBVH->EndPrimitive (aNodeIdx),
+      "Error! Invalid leaf node in high-level BVH (contains several objects)", Standard_False);
 
-    // Choose the best split (with minimum SAH cost)
-    for (int aSplit = 1; aSplit < THE_NUMBER_OF_BINS; ++aSplit)
-    {
-      int aLftCount = 0;
-      int aRghCount = 0;
-      OpenGl_AABB aLftAABB;
-      OpenGl_AABB aRghAABB;
-      for (int anIndex = 0; anIndex < aSplit; ++anIndex)
-      {
-        aLftCount += aBins[anIndex].Count;
-        aLftAABB.Combine (aBins[anIndex].Volume);
-      }
+    Standard_Integer anObjectIdx = aBVH->BegPrimitive (aNodeIdx);
 
-      for (int anIndex = aSplit; anIndex < THE_NUMBER_OF_BINS; ++anIndex)
-      {
-        aRghCount += aBins[anIndex].Count;
-        aRghAABB.Combine (aBins[anIndex].Volume);
-      }
+    Standard_ASSERT_RETURN (anObjectIdx < myObjects.Size(),
+      "Error! Invalid leaf node in high-level BVH (contains out-of-range object)", Standard_False);
 
-      // Simple SAH evaluation
-      float aCost = ( aLftAABB.Area() / aNodeArea ) * aLftCount +
-                    ( aRghAABB.Area() / aNodeArea ) * aRghCount;
+    OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
+      myObjects.ChangeValue (anObjectIdx).operator->());
 
-#ifdef BVH_DEBUG_OUTPUT
-      std::cout << "\t\tBin " << aSplit << ", Cost = " << aCost << std::endl;
-#endif
+    // Note: We overwrite node info record to store parameters
+    // of bottom-level BVH and triangulation of OpenGL element
 
-      if (aCost <= aMinSplitCost)
-      {
-        aMinSplitCost     = aCost;
-        aMinSplitAxis     = anAxis;
-        aMinSplitIndex    = aSplit;
-        aMinSplitLftAABB  = aLftAABB;
-        aMinSplitRghAABB  = aRghAABB;
-        aMinSplitLftCount = aLftCount;
-        aMinSplitRghCount = aRghCount;
-      }
-    }
-  }
+    aBVH->NodeInfoBuffer().at (aNodeIdx) = BVH_Vec4i (
+      anObjectIdx + 1 /* to keep leaf flag */, aBVHNodesOffset, aVerticesOffset, aElementsOffset);
 
-  if (aMinSplitAxis == -1)
-  {
-    // make outer (leaf) node
-    myTree.DataRcrdBuffer()[aTask.NodeToBuild].x() = 1;
-    return;
+    aVerticesOffset += (int)aTriangleSet->Vertices.size();
+    aElementsOffset += (int)aTriangleSet->Elements.size();
+    aBVHNodesOffset += aTriangleSet->BVH()->Length();
   }
 
-#ifdef BVH_DEBUG_OUTPUT
-  switch (aMinSplitAxis)
-  {
-  case 0:
-    std::cout << "\tSplit axis: X = " << aMinSplitIndex << std::endl;
-    break;
-  case 1:
-    std::cout << "\tSplit axis: Y = " << aMinSplitIndex << std::endl;
-    break;
-  case 2:
-    std::cout << "\tSplit axis: Z = " << aMinSplitIndex << std::endl;
-    break;
-  }
-#endif
-
-  int aMiddle = SplitTriangles (theGeometry, aTask.BegTriangle, aTask.EndTriangle,
-                                aNode, aMinSplitIndex - 1, aMinSplitAxis);
-
-#ifdef BVH_DEBUG_OUTPUT
-  std::cout << "\tLeft child: [" << aTask.BegTriangle << ", "
-                      << aMiddle - 1 << "]" << std::endl;
+  return Standard_True;
+}
 
-  std::cout << "\tRight child: [" << aMiddle << ", "
-                      << aTask.EndTriangle << "]" << std::endl;
-#endif
+// =======================================================================
+// function : AccelerationOffset
+// purpose  : Returns offset of bottom-level BVH for given leaf node
+// =======================================================================
+Standard_Integer OpenGl_RaytraceGeometry::AccelerationOffset (Standard_Integer theNodeIdx)
+{
+  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
 
-#define BVH_SIDE_LFT 1
-#define BVH_SIDE_RGH 2
+  if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
+    return INVALID_OFFSET;
 
-  // Setting up tasks for child nodes
-  for (int aSide = BVH_SIDE_LFT; aSide <= BVH_SIDE_RGH; ++aSide)
-  {
-    OpenGl_RTVec4f aMinPoint = (aSide == BVH_SIDE_LFT)
-                             ? aMinSplitLftAABB.CornerMin()
-                             : aMinSplitRghAABB.CornerMin();
-    OpenGl_RTVec4f aMaxPoint = (aSide == BVH_SIDE_LFT)
-                             ? aMinSplitLftAABB.CornerMax()
-                             : aMinSplitRghAABB.CornerMax();
-
-    int aBegTriangle = (aSide == BVH_SIDE_LFT)
-                     ? aTask.BegTriangle
-                     : aMiddle;
-    int aEndTriangle = (aSide == BVH_SIDE_LFT)
-                     ? aMiddle - 1
-                     : aTask.EndTriangle;
-
-    OpenGl_BVHNode aChild (aMinPoint, aMaxPoint, aBegTriangle, aEndTriangle);
-    aChild.SetLevel (aNode.Level() + 1);
-
-    // Check to see if child node must be split
-    const int aNbTriangles = (aSide == BVH_SIDE_LFT)
-                           ? aMinSplitLftCount
-                           : aMinSplitRghCount;
-
-    const int isChildALeaf = (aNbTriangles <= THE_MAX_LEAF_TRIANGLES) || (aNode.Level() >= myMaxDepth);
-    if (isChildALeaf)
-      aChild.SetOuter();
-    else
-      aChild.SetInner();
-
-    const int aChildIndex = myTree.PushNode (aChild);
-
-    // Modify parent node
-    myTree.DataRcrdBuffer()[aTask.NodeToBuild].x() = 0; // inner node flag
-    if (aSide == BVH_SIDE_LFT)
-      myTree.DataRcrdBuffer()[aTask.NodeToBuild].y() = aChildIndex; // left child
-    else
-      myTree.DataRcrdBuffer()[aTask.NodeToBuild].z() = aChildIndex; // right child
-
-    // Make new building task
-    if (!isChildALeaf)
-      myNodeTasksQueue.push_back (OpenGl_BVHNodeTask (aChildIndex, aBegTriangle, aEndTriangle));
-  }
+  return aBVH->NodeInfoBuffer().at (theNodeIdx).y();
 }
 
 // =======================================================================
-// function : SplitTriangles
-// purpose  : Splits node triangles into two intervals for child nodes
+// function : VerticesOffset
+// purpose  : Returns offset of triangulation vertices for given leaf node
 // =======================================================================
-int OpenGl_BinnedBVHBuilder::SplitTriangles (OpenGl_RaytraceScene& theGeometry,
-                                             const int             theBegTriangle,
-                                             const int             theEndTriangle,
-                                             OpenGl_BVHNode&       theNode,
-                                             int                   theBin,
-                                             const int             theAxis)
+Standard_Integer OpenGl_RaytraceGeometry::VerticesOffset (Standard_Integer theNodeIdx)
 {
-  int aLftIndex (theBegTriangle);
-  int aRghIndex (theEndTriangle);
+  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
 
-  const float aMin = theNode.MinPoint()[theAxis];
-  const float aMax = theNode.MaxPoint()[theAxis];
+  if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
+    return INVALID_OFFSET;
 
-  const float aStep = (aMax - aMin) / THE_NUMBER_OF_BINS;
-
-  do
-  {
-    while ((int )floorf ((theGeometry.CenterAxis (aLftIndex, theAxis) - aMin) / aStep) <= theBin
-              && aLftIndex < theEndTriangle)
-    {
-      ++aLftIndex;
-    }
-    while ((int )floorf ((theGeometry.CenterAxis (aRghIndex, theAxis) - aMin) / aStep) >  theBin
-              && aRghIndex > theBegTriangle)
-    {
-      --aRghIndex;
-    }
+  return aBVH->NodeInfoBuffer().at (theNodeIdx).z();
+}
 
-    if (aLftIndex <= aRghIndex)
-    {
-      if (aLftIndex != aRghIndex)
-      {
-        OpenGl_RTVec4i aLftTrg = theGeometry.Triangles[aLftIndex];
-        OpenGl_RTVec4i aRghTrg = theGeometry.Triangles[aRghIndex];
-        theGeometry.Triangles[aLftIndex] = aRghTrg;
-        theGeometry.Triangles[aRghIndex] = aLftTrg;
-      }
+// =======================================================================
+// function : ElementsOffset
+// purpose  : Returns offset of triangulation elements for given leaf node
+// =======================================================================
+Standard_Integer OpenGl_RaytraceGeometry::ElementsOffset (Standard_Integer theNodeIdx)
+{
+  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
 
-      aLftIndex++; aRghIndex--;
-    }
-  } while (aLftIndex <= aRghIndex);
+  if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
+    return INVALID_OFFSET;
 
-  return aLftIndex;
+  return aBVH->NodeInfoBuffer().at (theNodeIdx).w();
 }
 
 // =======================================================================
-// function : GetSubVolumes
-// purpose  : Arranges node triangles into bins
+// function : TriangleSet
+// purpose  : Returns triangulation data for given leaf node
 // =======================================================================
-void OpenGl_BinnedBVHBuilder::GetSubVolumes (OpenGl_RaytraceScene& theGeometry,
-                                             const OpenGl_BVHNode& theNode,
-                                             OpenGl_BinVector&     theBins,
-                                             const int             theAxis)
+OpenGl_TriangleSet* OpenGl_RaytraceGeometry::TriangleSet (Standard_Integer theNodeIdx)
 {
-  const float aMin = theNode.MinPoint()[theAxis];
-  const float aMax = theNode.MaxPoint()[theAxis];
+  const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = BVH();
 
-  const float aStep = (aMax - aMin) / THE_NUMBER_OF_BINS;
+  if (theNodeIdx >= aBVH->Length() || !aBVH->IsOuter (theNodeIdx))
+    return NULL;
 
-  for (int aTri = theNode.BegTriangle(); aTri <= theNode.EndTriangle(); ++aTri)
-  {
-    float aCenter = theGeometry.CenterAxis (aTri, theAxis);
-    int aBinIndex = (int )floorf ((aCenter - aMin) * ( 1.0f / aStep));
-    if (aBinIndex < 0)
-    {
-      aBinIndex = 0;
-    }
-    else if (aBinIndex >= THE_NUMBER_OF_BINS)
-    {
-      aBinIndex = THE_NUMBER_OF_BINS - 1;
-    }
+  if (aBVH->NodeInfoBuffer().at (theNodeIdx).x() > myObjects.Size())
+    return NULL;
 
-    theBins[aBinIndex].Count++;
-    theBins[aBinIndex].Volume.Combine (theGeometry.Box (aTri));
-  }
+  return dynamic_cast<OpenGl_TriangleSet*> (myObjects.ChangeValue (
+    aBVH->NodeInfoBuffer().at (theNodeIdx).x() - 1).operator->());
 }
 
 namespace OpenGl_Raytrace
@@ -713,12 +344,9 @@ namespace OpenGl_Raytrace
   // =======================================================================
   Standard_Boolean IsRaytracedElement (const OpenGl_ElementNode* theNode)
   {
-    if (TelParray == theNode->type)
-    {
-      OpenGl_PrimitiveArray* anArray = dynamic_cast< OpenGl_PrimitiveArray* > (theNode->elem);
-      return anArray->PArray()->type >= TelPolygonsArrayType;
-    }
-    return Standard_False;
+    OpenGl_PrimitiveArray* anArray = dynamic_cast< OpenGl_PrimitiveArray* > (theNode->elem);
+    return anArray != NULL
+        && anArray->PArray()->type >= TelPolygonsArrayType;
   }
 
   // =======================================================================
@@ -742,12 +370,12 @@ namespace OpenGl_Raytrace
   // function : IsRaytracedStructure
   // purpose  : Checks to see if the structure contains ray-trace geometry
   // =======================================================================
-  Standard_Boolean IsRaytracedStructure (const OpenGl_Structure *theStructure)
+  Standard_Boolean IsRaytracedStructure (const OpenGl_StructuretheStructure)
   {
-    for (OpenGl_ListOfGroup::Iterator anItg (theStructure->Groups());
-         anItg.More(); anItg.Next())
+    for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups());
+         aGroupIter.More(); aGroupIter.Next())
     {
-      if (anItg.Value()->IsRaytracable())
+      if (aGroupIter.Value()->IsRaytracable())
         return Standard_True;
     }
     for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures());
@@ -759,5 +387,3 @@ namespace OpenGl_Raytrace
     return Standard_False;
   }
 }
-
-#endif