0024520: Implementing affine transformations in ray-tracing
authorduv <duv@opencascade.com>
Mon, 31 Mar 2014 12:36:21 +0000 (16:36 +0400)
committerapn <apn@opencascade.com>
Thu, 10 Apr 2014 15:21:21 +0000 (19:21 +0400)
src/OpenGl/OpenGl_SceneGeometry.hxx
src/OpenGl/OpenGl_Workspace.hxx
src/OpenGl/OpenGl_Workspace_Raytrace.cxx
src/Shaders/RaytraceBase.fs

index 6a6f793..f3af8b1 100755 (executable)
@@ -122,22 +122,71 @@ class OpenGl_TriangleSet : public BVH_Triangulation<Standard_ShortReal, 4>
 {
 public:
 
-  BVH_Array4f Normals; //!< Array of vertex normals
+  //! Value of invalid material index to return in case of errors.
+  static const Standard_Integer INVALID_MATERIAL = -1;
 
 public:
 
   //! Creates new OpenGL element triangulation.
-  OpenGl_TriangleSet()
-  : BVH_Triangulation<Standard_ShortReal, 4>()
-  {
-    //
-  }
+  OpenGl_TriangleSet (const OpenGl_PrimitiveArray* theArray = NULL)
+  : BVH_Triangulation<Standard_ShortReal, 4>(),
+    myArray (theArray)
+   {
+     //
+   }
 
   //! Releases resources of OpenGL element triangulation.
   ~OpenGl_TriangleSet()
   {
     //
   }
+
+  //! Returns associated OpenGl structure.
+  const OpenGl_PrimitiveArray* AssociatedPArray() const
+  {
+    return myArray;
+  }
+
+  //! Returns material index of triangle set.
+  Standard_Integer MaterialIndex() const
+  {
+    if (Elements.size() == 0)
+      return INVALID_MATERIAL;
+
+    return Elements.front().w();
+  }
+
+  //! Sets material index for entire triangle set.
+  void SetMaterialIndex (Standard_Integer aMatID)
+  {
+    for (Standard_Size anIdx = 0; anIdx < Elements.size(); ++anIdx)
+      Elements[anIdx].w() = aMatID;
+  }
+
+  //! Returns AABB of primitive set.
+  BVH_BoxNt Box() const
+  {
+    const BVH_Transform<Standard_ShortReal, 4>* aTransform = 
+      dynamic_cast<const BVH_Transform<Standard_ShortReal, 4>* > (Properties().operator->());
+    BVH_BoxNt aBox = BVH_PrimitiveSet<Standard_ShortReal, 4>::Box(); 
+    if (aTransform)
+    {
+      return aTransform->Apply (aBox);
+    }
+    return aBox;
+  }
+
+public:
+
+  BVH_Array4f Normals; //!< Array of vertex normals.
+private:
+
+  const OpenGl_PrimitiveArray* myArray; //!< Reference to associated OpenGl structure.
+
 };
 
 //! Stores geometry of ray-tracing scene.
@@ -181,6 +230,15 @@ public:
   //! Clears ray-tracing geometry.
   void Clear();
 
+  //! Clears only ray-tracing materials.
+  void ClearMaterials()
+  {
+    std::vector<OpenGl_RaytraceMaterial,
+      NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
+    Materials.swap (anEmptyMaterials);
+  }
+
 public:
 
   //! Performs post-processing of high-level scene BVH.
index d2dbc07..3042912 100755 (executable)
@@ -242,6 +242,14 @@ protected:
     OpenGl_RT_FAIL
   };
 
+  //! Describes update mode (state).
+  enum GeomUpdateMode
+  {
+    OpenGl_GUM_CHECK,   //!< check if geometry update is necessary
+    OpenGl_GUM_PREPARE, //!< collect unchanged objects
+    OpenGl_GUM_UPDATE   //!< update raytracing data, rebuild changed objects
+  };
+
   //! Defines frequently used shader variables.
   enum ShaderVariableIndex
   {
@@ -272,6 +280,8 @@ protected:
     OpenGl_RT_uOffsetY,
     OpenGl_RT_uSamples,
 
+    OpenGl_RT_uEnvironmentEnable,
+
     OpenGl_RT_NbVariables // special field
   };
 
@@ -295,7 +305,9 @@ protected:
     OpenGl_RT_RaytraceMaterialTexture = 10,
     OpenGl_RT_RaytraceLightSrcTexture = 11,
 
-    OpenGl_RT_FSAAInputTexture = 12
+    OpenGl_RT_FSAAInputTexture = 12,
+
+    OpenGl_RT_SceneTransformTexture = 13
   };
 
   //! Tool class for management of shader sources.
@@ -348,7 +360,7 @@ protected:
 protected: //! @name methods related to ray-tracing
 
   //! Updates 3D scene geometry for ray-tracing.
-  Standard_Boolean UpdateRaytraceGeometry (Standard_Boolean theCheck);
+  Standard_Boolean UpdateRaytraceGeometry (GeomUpdateMode theMode);
 
   //! Checks to see if the structure is modified.
   Standard_Boolean CheckRaytraceStructure (const OpenGl_Structure* theStructure);
@@ -365,7 +377,7 @@ protected: //! @name methods related to ray-tracing
 
   //! Adds OpenGL primitive array to ray-traced scene geometry.
   OpenGl_TriangleSet* AddRaytracePrimitiveArray (
-    const CALL_DEF_PARRAY* theArray, int theMatID, const Standard_ShortReal* theTrans);
+    const OpenGl_PrimitiveArray* theArray, int theMatID, const Standard_ShortReal* theTrans);
 
   //! Adds vertex indices from OpenGL primitive array to ray-traced scene geometry.
   Standard_Boolean AddRaytraceVertexIndices (OpenGl_TriangleSet* theSet,
@@ -475,6 +487,8 @@ protected: //! @name fields related to ray-tracing
   Handle(OpenGl_TextureBufferArb) mySceneMinPointTexture;
   //! Texture buffer of maximum points of high-level BVH nodes.
   Handle(OpenGl_TextureBufferArb) mySceneMaxPointTexture;
+  //! Texture buffer of transformations of high-level BVH nodes.
+  Handle(OpenGl_TextureBufferArb) mySceneTransformTexture;
 
   //! Texture buffer of data records of bottom-level BVH nodes.
   Handle(OpenGl_TextureBufferArb) myObjectNodeInfoTexture;
@@ -511,6 +525,9 @@ protected: //! @name fields related to ray-tracing
   //! State of OpenGL structures reflected to ray-tracing.
   std::map<const OpenGl_Structure*, Standard_Size> myStructureStates;
 
+  //! PrimitiveArray to TriangleSet map for scene partial update.
+  std::map<const OpenGl_PrimitiveArray*, OpenGl_TriangleSet*> myArrayToTrianglesMap;
+
   //! Cached locations of frequently used uniform variables.
   Standard_Integer myUniformLocations[2][OpenGl_RT_NbVariables];
 
index b03caad..602576f 100755 (executable)
@@ -55,35 +55,37 @@ BVH_Vec4f MatVecMult (const T m[16], const BVH_Vec4f& v)
 // function : UpdateRaytraceGeometry
 // purpose  : Updates 3D scene geometry for ray tracing
 // =======================================================================
-Standard_Boolean OpenGl_Workspace::UpdateRaytraceGeometry (Standard_Boolean theCheck)
+Standard_Boolean OpenGl_Workspace::UpdateRaytraceGeometry (GeomUpdateMode theMode)
 {
   if (myView.IsNull())
     return Standard_False;
 
-  // Note: In 'check' mode the scene geometry is analyzed for modifications
+  // Note: In 'check' mode (OpenGl_GUM_CHECK) the scene geometry is analyzed for modifications
   // This is light-weight procedure performed for each frame
 
-  if (!theCheck)
+  if (theMode == OpenGl_GUM_CHECK)
   {
-    myRaytraceGeometry.Clear();
+     if (myLayersModificationStatus != myView->LayerList().ModificationState())
+     {
+        return UpdateRaytraceGeometry (OpenGl_GUM_PREPARE);
+     }
+  } 
+  else if (theMode == OpenGl_GUM_PREPARE)
+  {
+    myRaytraceGeometry.ClearMaterials();
+    myArrayToTrianglesMap.clear();
 
     myIsRaytraceDataValid = Standard_False;
   }
-  else
-  {
-    if (myLayersModificationStatus != myView->LayerList().ModificationState())
-    {
-      return UpdateRaytraceGeometry (Standard_False);
-    }
-  }
-
-  Standard_ShortReal* aTransform (NULL);
 
   // The set of processed structures (reflected to ray-tracing)
   // This set is used to remove out-of-date records from the
   // hash map of structures
   std::set<const OpenGl_Structure*> anElements;
 
+  // Set of all currently visible and "raytracable" primitive arrays.
+  std::set<const OpenGl_PrimitiveArray*> anArrays;
+
   const OpenGl_LayerList& aList = myView->LayerList();
 
   for (OpenGl_SequenceOfLayers::Iterator anLayerIt (aList.Layers()); anLayerIt.More(); anLayerIt.Next())
@@ -101,16 +103,39 @@ Standard_Boolean OpenGl_Workspace::UpdateRaytraceGeometry (Standard_Boolean theC
 
       for (aStructIt.Init (aStructArray (anIndex)); aStructIt.More(); aStructIt.Next())
       {
+        Standard_ShortReal* aTransform (NULL);
+
         const OpenGl_Structure* aStructure = aStructIt.Value();
 
-        if (theCheck)
+        if (theMode == OpenGl_GUM_CHECK)
         {
           if (CheckRaytraceStructure (aStructure))
           {
-            return UpdateRaytraceGeometry (Standard_False);
+            return UpdateRaytraceGeometry (OpenGl_GUM_PREPARE);
           }
-        }
-        else
+        } 
+        else if (theMode == OpenGl_GUM_PREPARE)
+        {
+          if (!aStructure->IsRaytracable()
+           || !aStructure->IsVisible())
+            continue;
+
+          for (OpenGl_Structure::GroupIterator aGroupIter (aStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next())
+          {
+            // OpenGL elements from group (extract primitives arrays)
+            for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next)
+            {
+              OpenGl_PrimitiveArray* aPrimArray = dynamic_cast<OpenGl_PrimitiveArray*> (aNode->elem);
+
+              if (aPrimArray != NULL)
+              {
+                // Collect all primitive arrays in scene.
+                anArrays.insert (aPrimArray);
+              }
+            }
+          }
+        } 
+        else if (theMode == OpenGl_GUM_UPDATE)
         {
           if (!aStructure->IsRaytracable())
             continue;
@@ -129,11 +154,40 @@ Standard_Boolean OpenGl_Workspace::UpdateRaytraceGeometry (Standard_Boolean theC
 
           AddRaytraceStructure (aStructure, aTransform, anElements);
         }
+
+        delete [] aTransform;
       }
     }
   }
 
-  if (!theCheck)
+  if (theMode == OpenGl_GUM_PREPARE)
+  {
+    BVH_ObjectSet<Standard_ShortReal, 4>::BVH_ObjectList anUnchangedObjects;
+
+    // Leave only unchanged objects in myRaytraceGeometry so only their transforms and materials will be updated
+    // Objects which not in myArrayToTrianglesMap will be built from scratch.
+    for (Standard_Integer anObjectIdx = 0; anObjectIdx < myRaytraceGeometry.Objects().Size(); ++anObjectIdx)
+    {
+      OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
+        myRaytraceGeometry.Objects().ChangeValue (anObjectIdx).operator->());
+
+      // If primitive array of object not in "anArrays" set then it was hided or deleted.
+      // If primitive array present in "anArrays" set but we don't have associated object yet, then
+      // the object is new and still has to be built.
+      if ((aTriangleSet != NULL) && ((anArrays.find (aTriangleSet->AssociatedPArray())) != anArrays.end()))
+      {
+        anUnchangedObjects.Append (myRaytraceGeometry.Objects().Value (anObjectIdx));
+
+        myArrayToTrianglesMap[aTriangleSet->AssociatedPArray()] = aTriangleSet;
+      }
+    }
+
+    myRaytraceGeometry.Objects() = anUnchangedObjects;
+
+    return UpdateRaytraceGeometry (OpenGl_GUM_UPDATE);
+  }
+
+  if (theMode == OpenGl_GUM_UPDATE)
   {
     // Actualize the hash map of structures -- remove out-of-date records
     std::map<const OpenGl_Structure*, Standard_Size>::iterator anIter = myStructureStates.begin();
@@ -171,8 +225,6 @@ Standard_Boolean OpenGl_Workspace::UpdateRaytraceGeometry (Standard_Boolean theC
     return UploadRaytraceData();
   }
 
-  delete [] aTransform;
-
   return Standard_True;
 }
 
@@ -320,26 +372,62 @@ Standard_Boolean OpenGl_Workspace::AddRaytraceStructure (const OpenGl_Structure*
       else
       {
         OpenGl_PrimitiveArray* aPrimArray = dynamic_cast<OpenGl_PrimitiveArray*> (aNode->elem);
+
+        std::map<const OpenGl_PrimitiveArray*, OpenGl_TriangleSet*>::iterator aSetIter = myArrayToTrianglesMap.find (aPrimArray);
+
         if (aPrimArray != NULL)
         {
-          NCollection_Handle<BVH_Object<Standard_ShortReal, 4> > aSet =
-            AddRaytracePrimitiveArray (aPrimArray->PArray(), aMatID, theTransform);
+          if (aSetIter != myArrayToTrianglesMap.end())
+          {
+            OpenGl_TriangleSet* aSet = aSetIter->second;
+            BVH_Transform<Standard_ShortReal, 4>* aTransform = new BVH_Transform<Standard_ShortReal, 4>();
+
+            if (theTransform != NULL)
+            {
+              aTransform->SetTransform (*(reinterpret_cast<const BVH_Mat4f*> (theTransform)));
+            }
+          
+            aSet->SetProperties (aTransform);
+
+            if (aSet->MaterialIndex() != OpenGl_TriangleSet::INVALID_MATERIAL && aSet->MaterialIndex() != aMatID )
+            {
+              aSet->SetMaterialIndex (aMatID);
+            }
+          }
+          else
+          {
+            NCollection_Handle<BVH_Object<Standard_ShortReal, 4> > aSet =
+              AddRaytracePrimitiveArray (aPrimArray, aMatID, 0);
 
-          if (!aSet.IsNull())
-            myRaytraceGeometry.Objects().Append (aSet);
+            if (!aSet.IsNull())
+            {
+              BVH_Transform<Standard_ShortReal, 4>* aTransform = new BVH_Transform<Standard_ShortReal, 4>;
+
+              if (theTransform != NULL)
+              {
+                aTransform->SetTransform (*(reinterpret_cast<const BVH_Mat4f*> (theTransform)));
+              }
+
+              aSet->SetProperties (aTransform);
+
+              myRaytraceGeometry.Objects().Append (aSet);
+            }
+          }
         }
       }
     }
   }
 
-  Standard_ShortReal* aTransform (NULL);
+  Standard_ShortReal* aTransform = NULL;
 
   // Process all connected OpenGL structures
   for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures()); anIts.More(); anIts.Next())
   {
     if (anIts.Value()->Transformation()->mat != NULL)
     {
-      Standard_ShortReal* aTransform = new Standard_ShortReal[16];
+      if (aTransform == NULL)
+        aTransform = new Standard_ShortReal[16];
 
       for (Standard_Integer i = 0; i < 4; ++i)
         for (Standard_Integer j = 0; j < 4; ++j)
@@ -365,23 +453,25 @@ Standard_Boolean OpenGl_Workspace::AddRaytraceStructure (const OpenGl_Structure*
 // purpose  : Adds OpenGL primitive array to ray-traced scene geometry
 // =======================================================================
 OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (
-  const CALL_DEF_PARRAY* theArray, Standard_Integer theMatID, const Standard_ShortReal* theTransform)
+  const OpenGl_PrimitiveArray* theArray, Standard_Integer theMatID, const Standard_ShortReal* theTransform)
 {
-  if (theArray->type != TelPolygonsArrayType &&
-      theArray->type != TelTrianglesArrayType &&
-      theArray->type != TelQuadranglesArrayType &&
-      theArray->type != TelTriangleFansArrayType &&
-      theArray->type != TelTriangleStripsArrayType &&
-      theArray->type != TelQuadrangleStripsArrayType)
+  CALL_DEF_PARRAY* aPArray = theArray->PArray();
+
+  if (aPArray->type != TelPolygonsArrayType &&
+      aPArray->type != TelTrianglesArrayType &&
+      aPArray->type != TelQuadranglesArrayType &&
+      aPArray->type != TelTriangleFansArrayType &&
+      aPArray->type != TelTriangleStripsArrayType &&
+      aPArray->type != TelQuadrangleStripsArrayType)
   {
     return NULL;
   }
 
-  if (theArray->vertices == NULL)
+  if (aPArray->vertices == NULL)
     return NULL;
 
 #ifdef RAY_TRACE_PRINT_INFO
-  switch (theArray->type)
+  switch (aPArray->type)
   {
     case TelPolygonsArrayType:
       std::cout << "\tAdding TelPolygonsArrayType" << std::endl; break;
@@ -398,16 +488,16 @@ OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (
   }
 #endif
 
-  OpenGl_TriangleSet* aSet = new OpenGl_TriangleSet;
+  OpenGl_TriangleSet* aSet = new OpenGl_TriangleSet (theArray);
 
   {
-    aSet->Vertices.reserve (theArray->num_vertexs);
+    aSet->Vertices.reserve (aPArray->num_vertexs);
 
-    for (Standard_Integer aVert = 0; aVert < theArray->num_vertexs; ++aVert)
+    for (Standard_Integer aVert = 0; aVert < aPArray->num_vertexs; ++aVert)
     {
-      BVH_Vec4f aVertex (theArray->vertices[aVert].xyz[0],
-                         theArray->vertices[aVert].xyz[1],
-                         theArray->vertices[aVert].xyz[2],
+      BVH_Vec4f aVertex (aPArray->vertices[aVert].xyz[0],
+                         aPArray->vertices[aVert].xyz[1],
+                         aPArray->vertices[aVert].xyz[2],
                          1.f);
       if (theTransform)
         aVertex = MatVecMult (theTransform, aVertex);
@@ -415,20 +505,20 @@ OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (
       aSet->Vertices.push_back (aVertex);
     }
 
-    aSet->Normals.reserve (theArray->num_vertexs);
+    aSet->Normals.reserve (aPArray->num_vertexs);
 
-    for (Standard_Integer aNorm = 0; aNorm < theArray->num_vertexs; ++aNorm)
+    for (Standard_Integer aNorm = 0; aNorm < aPArray->num_vertexs; ++aNorm)
     {
       BVH_Vec4f aNormal;
 
       // Note: In case of absence of normals, the
       // renderer uses generated geometric normals
 
-      if (theArray->vnormals != NULL)
+      if (aPArray->vnormals != NULL)
       {
-        aNormal = BVH_Vec4f (theArray->vnormals[aNorm].xyz[0],
-                             theArray->vnormals[aNorm].xyz[1],
-                             theArray->vnormals[aNorm].xyz[2],
+        aNormal = BVH_Vec4f (aPArray->vnormals[aNorm].xyz[0],
+                             aPArray->vnormals[aNorm].xyz[1],
+                             aPArray->vnormals[aNorm].xyz[2],
                              0.f);
 
         if (theTransform)
@@ -438,24 +528,24 @@ OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (
       aSet->Normals.push_back (aNormal);
     }
 
-    if (theArray->num_bounds > 0)
+    if (aPArray->num_bounds > 0)
     {
   #ifdef RAY_TRACE_PRINT_INFO
-      std::cout << "\tNumber of bounds = " << theArray->num_bounds << std::endl;
+      std::cout << "\tNumber of bounds = " << aPArray->num_bounds << std::endl;
   #endif
 
       Standard_Integer aBoundStart = 0;
 
-      for (Standard_Integer aBound = 0; aBound < theArray->num_bounds; ++aBound)
+      for (Standard_Integer aBound = 0; aBound < aPArray->num_bounds; ++aBound)
       {
-        const Standard_Integer aVertNum = theArray->bounds[aBound];
+        const Standard_Integer aVertNum = aPArray->bounds[aBound];
 
   #ifdef RAY_TRACE_PRINT_INFO
         std::cout << "\tAdding indices from bound " << aBound << ": " <<
                                       aBoundStart << " .. " << aVertNum << std::endl;
   #endif
 
-        if (!AddRaytraceVertexIndices (aSet, theArray, aBoundStart, aVertNum, theMatID))
+        if (!AddRaytraceVertexIndices (aSet, aPArray, aBoundStart, aVertNum, theMatID))
         {
           delete aSet;
           return NULL;
@@ -466,13 +556,13 @@ OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (
     }
     else
     {
-      const Standard_Integer aVertNum = theArray->num_edges > 0 ? theArray->num_edges : theArray->num_vertexs;
+      const Standard_Integer aVertNum = aPArray->num_edges > 0 ? aPArray->num_edges : aPArray->num_vertexs;
 
   #ifdef RAY_TRACE_PRINT_INFO
         std::cout << "\tAdding indices from array: " << aVertNum << std::endl;
   #endif
 
-      if (!AddRaytraceVertexIndices (aSet, theArray, 0, aVertNum, theMatID))
+      if (!AddRaytraceVertexIndices (aSet, aPArray, 0, aVertNum, theMatID))
       {
         delete aSet;
         return NULL;
@@ -853,15 +943,14 @@ Standard_Boolean OpenGl_Workspace::UpdateRaytraceEnvironmentMap()
         myView->TextureEnv()->Bind (
           myGlContext, GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture);
 
-        aProgram->SetUniform (myGlContext, "uEnvironmentEnable", 1);
+        aProgram->SetUniform (myGlContext,
+          myUniformLocations[anIdx][OpenGl_RT_uEnvironmentEnable], 1);
       }
       else
       {
-        aProgram->SetUniform (myGlContext, "uEnvironmentEnable", 0);
+        aProgram->SetUniform (myGlContext,
+          myUniformLocations[anIdx][OpenGl_RT_uEnvironmentEnable], 0);
       }
-
-      aProgram->SetSampler (myGlContext,
-        "uEnvironmentMapTexture", OpenGl_RT_EnvironmentMapTexture);
     }
   }
 
@@ -1050,6 +1139,9 @@ Standard_Boolean OpenGl_Workspace::InitRaytraceResources()
       std::cout << "Info: Rebuild shaders with stack size: " << myTraversalStackSize << std::endl;
 #endif
 
+      // Change state to force update all uniforms.
+      ++myViewModificationStatus;
+
       TCollection_AsciiString aStackSizeStr =
         TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myTraversalStackSize);
 
@@ -1256,6 +1348,10 @@ Standard_Boolean OpenGl_Workspace::InitRaytraceResources()
         "uRaytraceMaterialTexture", OpenGl_RT_RaytraceMaterialTexture);
       aShaderProgram->SetSampler (myGlContext,
         "uRaytraceLightSrcTexture", OpenGl_RT_RaytraceLightSrcTexture);
+      aShaderProgram->SetSampler (myGlContext, 
+        "uSceneTransformTexture", OpenGl_RT_SceneTransformTexture);
+      aShaderProgram->SetSampler (myGlContext,
+        "uEnvironmentMapTexture", OpenGl_RT_EnvironmentMapTexture);
 
       if (anIndex == 1)
       {
@@ -1304,6 +1400,9 @@ Standard_Boolean OpenGl_Workspace::InitRaytraceResources()
         aShaderProgram->GetUniformLocation (myGlContext, "uOffsetY");
       myUniformLocations[anIndex][OpenGl_RT_uSamples] =
         aShaderProgram->GetUniformLocation (myGlContext, "uSamples");
+
+      myUniformLocations[anIndex][OpenGl_RT_uEnvironmentEnable] =
+        aShaderProgram->GetUniformLocation (myGlContext, "uEnvironmentEnable");
     }
 
     OpenGl_ShaderProgram::Unbind (myGlContext);
@@ -1371,6 +1470,8 @@ void OpenGl_Workspace::ReleaseRaytraceResources()
   NullifyResource (myGlContext, mySceneMinPointTexture);
   NullifyResource (myGlContext, mySceneMaxPointTexture);
 
+  NullifyResource (myGlContext, mySceneTransformTexture);
+
   NullifyResource (myGlContext, myObjectNodeInfoTexture);
   NullifyResource (myGlContext, myObjectMinPointTexture);
   NullifyResource (myGlContext, myObjectMaxPointTexture);
@@ -1408,10 +1509,12 @@ Standard_Boolean OpenGl_Workspace::UploadRaytraceData()
     mySceneNodeInfoTexture = new OpenGl_TextureBufferArb;
     mySceneMinPointTexture = new OpenGl_TextureBufferArb;
     mySceneMaxPointTexture = new OpenGl_TextureBufferArb;
+    mySceneTransformTexture = new OpenGl_TextureBufferArb;
 
     if (!mySceneNodeInfoTexture->Create (myGlContext)
-      || !mySceneMinPointTexture->Create (myGlContext)
-      || !mySceneMaxPointTexture->Create (myGlContext))
+     || !mySceneMinPointTexture->Create (myGlContext)
+     || !mySceneMaxPointTexture->Create (myGlContext)
+     || !mySceneTransformTexture->Create (myGlContext))
     {
 #ifdef RAY_TRACE_PRINT_INFO
       std::cout << "Error: Failed to create buffers for high-level scene BVH" << std::endl;
@@ -1490,6 +1593,34 @@ Standard_Boolean OpenGl_Workspace::UploadRaytraceData()
     return Standard_False;
   }
 
+  /////////////////////////////////////////////////////////////////////////////
+  // Write transform buffer
+
+  BVH_Mat4f* aNodeTransforms = new BVH_Mat4f[myRaytraceGeometry.Size()];
+  BVH_Mat4f anIdentity;
+
+  for (Standard_Integer anElemIndex = 0; anElemIndex < myRaytraceGeometry.Size(); ++anElemIndex)
+  {
+    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->());
+
+    Standard_ASSERT_RETURN (aTransform != NULL,
+      "OpenGl_TriangleSet does not contain transform", Standard_False);
+
+    aNodeTransforms[anElemIndex] = aTransform->Inversed();
+
+  }
+
+  aResult &= mySceneTransformTexture->Init (myGlContext, 4,
+    myRaytraceGeometry.Size() * 4, reinterpret_cast<const GLfloat*> (aNodeTransforms));
+
+  delete[] aNodeTransforms;
+
+  /////////////////////////////////////////////////////////////////////////////
+
   Standard_Size aTotalVerticesNb = 0;
   Standard_Size aTotalElementsNb = 0;
   Standard_Size aTotalBVHNodesNb = 0;
@@ -1658,6 +1789,9 @@ Standard_Boolean OpenGl_Workspace::UploadRaytraceData()
   aMemUsed += static_cast<Standard_ShortReal> (
     myRaytraceGeometry.BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec4f));
 
+  aMemUsed += static_cast<Standard_ShortReal> (
+    aTransformsNb * sizeof (BVH_Vec4f) * 4);
+
   std::cout << "GPU Memory Used (MB): ~" << aMemUsed / 1048576 << std::endl;
 
 #endif
@@ -1764,6 +1898,7 @@ Standard_Boolean OpenGl_Workspace::RunRaytraceShaders (const Graphic3d_CView& th
   myGeometryTriangTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture);
   myRaytraceMaterialTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture);
   myRaytraceLightSrcTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture);
+  mySceneTransformTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture);
 
   if (theCView.IsAntialiasingEnabled) // render source image to FBO
   {
@@ -1870,6 +2005,7 @@ Standard_Boolean OpenGl_Workspace::RunRaytraceShaders (const Graphic3d_CView& th
     myUniformLocations[1][OpenGl_RT_aPosition], 3, GL_FLOAT, GL_FALSE, 0, NULL);
 
   // Perform multi-pass adaptive FSAA using ping-pong technique
+  // rotated grid AA always uses 4 samples
   for (Standard_Integer anIt = 0; anIt < 4; ++anIt)
   {
     GLfloat aOffsetX = 1.f / theSizeX;
@@ -1934,7 +2070,7 @@ Standard_Boolean OpenGl_Workspace::Raytrace (const Graphic3d_CView& theCView,
                                              const Standard_Boolean theToSwap,
                                              OpenGl_FrameBuffer*    theFrameBuffer)
 {
-  if (!UpdateRaytraceGeometry (Standard_True))
+  if (!UpdateRaytraceGeometry (OpenGl_GUM_CHECK))
     return Standard_False;
 
   if (!InitRaytraceResources())
@@ -1978,11 +2114,8 @@ Standard_Boolean OpenGl_Workspace::Raytrace (const Graphic3d_CView& theCView,
                 aOrigins,
                 aDirects);
 
-  // Draw background
-  glPushAttrib (GL_ENABLE_BIT |
-                GL_CURRENT_BIT |
-                GL_COLOR_BUFFER_BIT |
-                GL_DEPTH_BUFFER_BIT);
+  Standard_Boolean wasBlendingEnabled = glIsEnabled (GL_BLEND);
+  Standard_Boolean wasDepthTestEnabled = glIsEnabled (GL_DEPTH_TEST);
 
   glDisable (GL_DEPTH_TEST);
 
@@ -2029,10 +2162,11 @@ Standard_Boolean OpenGl_Workspace::Raytrace (const Graphic3d_CView& theCView,
     myRaytraceScreenQuad.Unbind (myGlContext);
   }
 
-  if (theFrameBuffer != NULL)
-    theFrameBuffer->UnbindBuffer (myGlContext);
+  if (!wasBlendingEnabled)
+    glDisable (GL_BLEND);
 
-  glPopAttrib();
+  if (wasDepthTestEnabled)
+    glEnable (GL_DEPTH_TEST);
 
   // Swap the buffers
   if (theToSwap)
index 1edc7a2..1050478 100644 (file)
@@ -25,6 +25,8 @@ uniform isamplerBuffer uSceneNodeInfoTexture;
 uniform samplerBuffer uSceneMinPointTexture;
 //! Texture buffer of maximum points of high-level BVH nodes.
 uniform samplerBuffer uSceneMaxPointTexture;
+//! Texture buffer of transformations of high-level BVH nodes.
+uniform samplerBuffer uSceneTransformTexture;
 
 //! Texture buffer of data records of bottom-level BVH nodes.
 uniform isamplerBuffer uObjectNodeInfoTexture;
@@ -99,6 +101,38 @@ struct SIntersect
 #define AXIS_Y vec3 (0.f, 1.f, 0.f)
 #define AXIS_Z vec3 (0.f, 0.f, 1.f)
 
+
+// =======================================================================
+// function : MatrixRowMultiply
+// purpose  : Multiplies a vector by matrix
+// =======================================================================
+vec3 MatrixRowMultiply (in vec4 v,
+                        in vec4 m0,
+                        in vec4 m1,
+                        in vec4 m2,
+                        in vec4 m3)
+{
+  return vec3 (dot (m0, v),
+               dot (m1, v),
+               dot (m2, v));
+}
+
+
+// =======================================================================
+// function : MatrixColMultiply
+// purpose  : Multiplies a vector by matrix
+// =======================================================================
+vec3 MatrixColMultiply (in vec4 v,
+                        in vec4 m0,
+                        in vec4 m1,
+                        in vec4 m2,
+                        in vec4 m3)
+{
+  return vec3 (m0[0] * v.x + m1[0] * v.y + m2[0] * v.z + m3[0] * v.w,
+               m0[1] * v.x + m1[1] * v.y + m2[1] * v.z + m3[1] * v.w,
+               m0[2] * v.x + m1[2] * v.y + m2[2] * v.z + m3[2] * v.w);
+}
+
 /////////////////////////////////////////////////////////////////////////////////////////
 // Functions for compute ray-object intersection
 
@@ -171,12 +205,12 @@ float IntersectTriangle (in SRay theRay,
                int(theUV.x + theUV.y <= 1.f)) ? aTime : MAXFLOAT;
 }
 
-//! Global stack shared between traversal functions.
-int Stack[STACK_SIZE];
-
 //! Identifies the absence of intersection.
 #define INALID_HIT ivec4 (-1)
 
+//! Global stack shared between traversal functions.
+int Stack[STACK_SIZE];
+
 // =======================================================================
 // function : ObjectNearestHit
 // purpose  : Finds intersection with nearest object triangle
@@ -251,7 +285,7 @@ ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgO
     {
       vec3 aNormal;
       vec2 aParams;
-            
+
       for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
       {
         ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
@@ -391,7 +425,7 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
 // function : SceneNearestHit
 // purpose  : Finds intersection with nearest scene triangle
 // =======================================================================
-ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit)
+ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theObjectId)
 {
   int aHead = -1; // stack pointer
   int aNode =  0; // node to visit
@@ -418,8 +452,29 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
       
       if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
       {
+        // fetch object transformation
+        int anObjectId = aData.x - 1;
+        vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
+        vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
+        vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
+        vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
+
+        SRay aNewRay;
+
+        aNewRay.Origin = MatrixColMultiply (vec4 (theRay.Origin, 1.f), 
+          aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
+
+        aNewRay.Direct = MatrixColMultiply (vec4 (theRay.Direct, 0.f), 
+          aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
+
+        vec3 aNewInverse = 1.f / max (abs (aNewRay.Direct), SMALL);
+        
+        aNewInverse.x = aNewRay.Direct.x < 0.f ? -aNewInverse.x : aNewInverse.x;
+        aNewInverse.y = aNewRay.Direct.y < 0.f ? -aNewInverse.y : aNewInverse.y;
+        aNewInverse.z = aNewRay.Direct.z < 0.f ? -aNewInverse.z : aNewInverse.z;
+
         ivec4 aTriIndex = ObjectNearestHit (
-          aData.y, aData.z, aData.w, theRay, theInverse, theHit, aHead);
+          aData.y, aData.z, aData.w, aNewRay, aNewInverse, theHit, aHead);
 
         if (aTriIndex.x != -1)
         {
@@ -427,6 +482,8 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH
                               aTriIndex.y + aData.z,  // vertex 1
                               aTriIndex.z + aData.z,  // vertex 2
                               aTriIndex.w);           // material
+
+          theObjectId = anObjectId;
         }
       }
       
@@ -509,8 +566,29 @@ float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
 
     if (aData.x != 0) // if leaf node
     {
+      // fetch object transformation
+      int anObjectId = aData.x - 1;
+      vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
+      vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
+      vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
+      vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
+
+      SRay aNewRay;
+
+      aNewRay.Origin = MatrixColMultiply (vec4 (theRay.Origin, 1.f), 
+        aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
+
+      aNewRay.Direct = MatrixColMultiply (vec4 (theRay.Direct, 0.f), 
+        aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
+
+      vec3 aNewInverse = 1.f / max (abs (aNewRay.Direct), SMALL);
+      
+      aNewInverse.x = aNewRay.Direct.x < 0.f ? -aNewInverse.x : aNewInverse.x;
+      aNewInverse.y = aNewRay.Direct.y < 0.f ? -aNewInverse.y : aNewInverse.y;
+      aNewInverse.z = aNewRay.Direct.z < 0.f ? -aNewInverse.z : aNewInverse.z;
+
       bool isShadow = 0.f == ObjectAnyHit (
-        aData.y, aData.z, aData.w, theRay, theInverse, theDistance, aHead);
+        aData.y, aData.z, aData.w, aNewRay, aNewInverse, theDistance, aHead);
         
       if (aHead < 0 || isShadow)
         return isShadow ? 0.f : 1.f;
@@ -624,12 +702,14 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
 {
   vec3 aResult = vec3 (0.f);
   vec4 aWeight = vec4 (1.f);
+
+  int anObjectId;
   
   for (int aDepth = 0; aDepth < 5; ++aDepth)
   {
     SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
     
-    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit);
+    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
 
     if (aTriIndex.x == -1)
     {
@@ -667,6 +747,14 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
       uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w)));
       
     vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
+
+    vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
+    vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
+    vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
+    vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
+
+    aNormal = MatrixRowMultiply (vec4 (aNormal, 0.f), aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3);
+    aNormal = normalize (aNormal);
     
     aHit.Normal = normalize (aHit.Normal);