From 84c71f29e40f243ea0c80cc4e313abd8c352f643 Mon Sep 17 00:00:00 2001 From: duv Date: Mon, 31 Mar 2014 16:36:21 +0400 Subject: [PATCH] 0024520: Implementing affine transformations in ray-tracing --- src/OpenGl/OpenGl_SceneGeometry.hxx | 70 +++++- src/OpenGl/OpenGl_Workspace.hxx | 23 +- src/OpenGl/OpenGl_Workspace_Raytrace.cxx | 274 +++++++++++++++++------ src/Shaders/RaytraceBase.fs | 104 ++++++++- 4 files changed, 384 insertions(+), 87 deletions(-) diff --git a/src/OpenGl/OpenGl_SceneGeometry.hxx b/src/OpenGl/OpenGl_SceneGeometry.hxx index 6a6f793fcc..f3af8b191b 100755 --- a/src/OpenGl/OpenGl_SceneGeometry.hxx +++ b/src/OpenGl/OpenGl_SceneGeometry.hxx @@ -122,22 +122,71 @@ class OpenGl_TriangleSet : public BVH_Triangulation { 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() - { - // - } + OpenGl_TriangleSet (const OpenGl_PrimitiveArray* theArray = NULL) + : BVH_Triangulation(), + 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* aTransform = + dynamic_cast* > (Properties().operator->()); + + BVH_BoxNt aBox = BVH_PrimitiveSet::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 > anEmptyMaterials; + + Materials.swap (anEmptyMaterials); + } + public: //! Performs post-processing of high-level scene BVH. diff --git a/src/OpenGl/OpenGl_Workspace.hxx b/src/OpenGl/OpenGl_Workspace.hxx index d2dbc07804..3042912b08 100755 --- a/src/OpenGl/OpenGl_Workspace.hxx +++ b/src/OpenGl/OpenGl_Workspace.hxx @@ -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 myStructureStates; + //! PrimitiveArray to TriangleSet map for scene partial update. + std::map myArrayToTrianglesMap; + //! Cached locations of frequently used uniform variables. Standard_Integer myUniformLocations[2][OpenGl_RT_NbVariables]; diff --git a/src/OpenGl/OpenGl_Workspace_Raytrace.cxx b/src/OpenGl/OpenGl_Workspace_Raytrace.cxx index b03caad556..602576fc96 100755 --- a/src/OpenGl/OpenGl_Workspace_Raytrace.cxx +++ b/src/OpenGl/OpenGl_Workspace_Raytrace.cxx @@ -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 anElements; + // Set of all currently visible and "raytracable" primitive arrays. + std::set 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 (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::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 ( + 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::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 (aNode->elem); + + std::map::iterator aSetIter = myArrayToTrianglesMap.find (aPrimArray); + if (aPrimArray != NULL) { - NCollection_Handle > aSet = - AddRaytracePrimitiveArray (aPrimArray->PArray(), aMatID, theTransform); + if (aSetIter != myArrayToTrianglesMap.end()) + { + OpenGl_TriangleSet* aSet = aSetIter->second; + + BVH_Transform* aTransform = new BVH_Transform(); - if (!aSet.IsNull()) - myRaytraceGeometry.Objects().Append (aSet); + if (theTransform != NULL) + { + aTransform->SetTransform (*(reinterpret_cast (theTransform))); + } + + aSet->SetProperties (aTransform); + + if (aSet->MaterialIndex() != OpenGl_TriangleSet::INVALID_MATERIAL && aSet->MaterialIndex() != aMatID ) + { + aSet->SetMaterialIndex (aMatID); + } + } + else + { + NCollection_Handle > aSet = + AddRaytracePrimitiveArray (aPrimArray, aMatID, 0); + + if (!aSet.IsNull()) + { + BVH_Transform* aTransform = new BVH_Transform; + + if (theTransform != NULL) + { + aTransform->SetTransform (*(reinterpret_cast (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 ( + myRaytraceGeometry.Objects().ChangeValue (anElemIndex).operator->()); + + const BVH_Transform* aTransform = + dynamic_cast* > (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 (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 ( myRaytraceGeometry.BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec4f)); + aMemUsed += static_cast ( + 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) diff --git a/src/Shaders/RaytraceBase.fs b/src/Shaders/RaytraceBase.fs index 1edc7a2f0a..1050478d53 100644 --- a/src/Shaders/RaytraceBase.fs +++ b/src/Shaders/RaytraceBase.fs @@ -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);