1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-08 18:40:55 +03:00

0024520: Implementing affine transformations in ray-tracing

This commit is contained in:
duv 2014-03-31 16:36:21 +04:00 committed by apn
parent ea095e0edb
commit 84c71f29e4
4 changed files with 384 additions and 87 deletions

View File

@ -122,22 +122,71 @@ class OpenGl_TriangleSet : public BVH_Triangulation<Standard_ShortReal, 4>
{ {
public: 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: public:
//! Creates new OpenGL element triangulation. //! Creates new OpenGL element triangulation.
OpenGl_TriangleSet() OpenGl_TriangleSet (const OpenGl_PrimitiveArray* theArray = NULL)
: BVH_Triangulation<Standard_ShortReal, 4>() : BVH_Triangulation<Standard_ShortReal, 4>(),
{ myArray (theArray)
// {
} //
}
//! Releases resources of OpenGL element triangulation. //! Releases resources of OpenGL element triangulation.
~OpenGl_TriangleSet() ~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. //! Stores geometry of ray-tracing scene.
@ -181,6 +230,15 @@ public:
//! Clears ray-tracing geometry. //! Clears ray-tracing geometry.
void Clear(); void Clear();
//! Clears only ray-tracing materials.
void ClearMaterials()
{
std::vector<OpenGl_RaytraceMaterial,
NCollection_StdAllocator<OpenGl_RaytraceMaterial> > anEmptyMaterials;
Materials.swap (anEmptyMaterials);
}
public: public:
//! Performs post-processing of high-level scene BVH. //! Performs post-processing of high-level scene BVH.

View File

@ -242,6 +242,14 @@ protected:
OpenGl_RT_FAIL 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. //! Defines frequently used shader variables.
enum ShaderVariableIndex enum ShaderVariableIndex
{ {
@ -272,6 +280,8 @@ protected:
OpenGl_RT_uOffsetY, OpenGl_RT_uOffsetY,
OpenGl_RT_uSamples, OpenGl_RT_uSamples,
OpenGl_RT_uEnvironmentEnable,
OpenGl_RT_NbVariables // special field OpenGl_RT_NbVariables // special field
}; };
@ -295,7 +305,9 @@ protected:
OpenGl_RT_RaytraceMaterialTexture = 10, OpenGl_RT_RaytraceMaterialTexture = 10,
OpenGl_RT_RaytraceLightSrcTexture = 11, OpenGl_RT_RaytraceLightSrcTexture = 11,
OpenGl_RT_FSAAInputTexture = 12 OpenGl_RT_FSAAInputTexture = 12,
OpenGl_RT_SceneTransformTexture = 13
}; };
//! Tool class for management of shader sources. //! Tool class for management of shader sources.
@ -348,7 +360,7 @@ protected:
protected: //! @name methods related to ray-tracing protected: //! @name methods related to ray-tracing
//! Updates 3D scene geometry for 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. //! Checks to see if the structure is modified.
Standard_Boolean CheckRaytraceStructure (const OpenGl_Structure* theStructure); 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. //! Adds OpenGL primitive array to ray-traced scene geometry.
OpenGl_TriangleSet* AddRaytracePrimitiveArray ( 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. //! Adds vertex indices from OpenGL primitive array to ray-traced scene geometry.
Standard_Boolean AddRaytraceVertexIndices (OpenGl_TriangleSet* theSet, Standard_Boolean AddRaytraceVertexIndices (OpenGl_TriangleSet* theSet,
@ -475,6 +487,8 @@ protected: //! @name fields related to ray-tracing
Handle(OpenGl_TextureBufferArb) mySceneMinPointTexture; Handle(OpenGl_TextureBufferArb) mySceneMinPointTexture;
//! Texture buffer of maximum points of high-level BVH nodes. //! Texture buffer of maximum points of high-level BVH nodes.
Handle(OpenGl_TextureBufferArb) mySceneMaxPointTexture; 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. //! Texture buffer of data records of bottom-level BVH nodes.
Handle(OpenGl_TextureBufferArb) myObjectNodeInfoTexture; Handle(OpenGl_TextureBufferArb) myObjectNodeInfoTexture;
@ -511,6 +525,9 @@ protected: //! @name fields related to ray-tracing
//! State of OpenGL structures reflected to ray-tracing. //! State of OpenGL structures reflected to ray-tracing.
std::map<const OpenGl_Structure*, Standard_Size> myStructureStates; 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. //! Cached locations of frequently used uniform variables.
Standard_Integer myUniformLocations[2][OpenGl_RT_NbVariables]; Standard_Integer myUniformLocations[2][OpenGl_RT_NbVariables];

View File

@ -55,35 +55,37 @@ BVH_Vec4f MatVecMult (const T m[16], const BVH_Vec4f& v)
// function : UpdateRaytraceGeometry // function : UpdateRaytraceGeometry
// purpose : Updates 3D scene geometry for ray tracing // 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()) if (myView.IsNull())
return Standard_False; 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 // 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; 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) // The set of processed structures (reflected to ray-tracing)
// This set is used to remove out-of-date records from the // This set is used to remove out-of-date records from the
// hash map of structures // hash map of structures
std::set<const OpenGl_Structure*> anElements; 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(); const OpenGl_LayerList& aList = myView->LayerList();
for (OpenGl_SequenceOfLayers::Iterator anLayerIt (aList.Layers()); anLayerIt.More(); anLayerIt.Next()) 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()) for (aStructIt.Init (aStructArray (anIndex)); aStructIt.More(); aStructIt.Next())
{ {
Standard_ShortReal* aTransform (NULL);
const OpenGl_Structure* aStructure = aStructIt.Value(); const OpenGl_Structure* aStructure = aStructIt.Value();
if (theCheck) if (theMode == OpenGl_GUM_CHECK)
{ {
if (CheckRaytraceStructure (aStructure)) 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()) if (!aStructure->IsRaytracable())
continue; continue;
@ -129,11 +154,40 @@ Standard_Boolean OpenGl_Workspace::UpdateRaytraceGeometry (Standard_Boolean theC
AddRaytraceStructure (aStructure, aTransform, anElements); 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 // Actualize the hash map of structures -- remove out-of-date records
std::map<const OpenGl_Structure*, Standard_Size>::iterator anIter = myStructureStates.begin(); 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(); return UploadRaytraceData();
} }
delete [] aTransform;
return Standard_True; return Standard_True;
} }
@ -320,26 +372,62 @@ Standard_Boolean OpenGl_Workspace::AddRaytraceStructure (const OpenGl_Structure*
else else
{ {
OpenGl_PrimitiveArray* aPrimArray = dynamic_cast<OpenGl_PrimitiveArray*> (aNode->elem); OpenGl_PrimitiveArray* aPrimArray = dynamic_cast<OpenGl_PrimitiveArray*> (aNode->elem);
std::map<const OpenGl_PrimitiveArray*, OpenGl_TriangleSet*>::iterator aSetIter = myArrayToTrianglesMap.find (aPrimArray);
if (aPrimArray != NULL) if (aPrimArray != NULL)
{ {
NCollection_Handle<BVH_Object<Standard_ShortReal, 4> > aSet = if (aSetIter != myArrayToTrianglesMap.end())
AddRaytracePrimitiveArray (aPrimArray->PArray(), aMatID, theTransform); {
OpenGl_TriangleSet* aSet = aSetIter->second;
if (!aSet.IsNull()) BVH_Transform<Standard_ShortReal, 4>* aTransform = new BVH_Transform<Standard_ShortReal, 4>();
myRaytraceGeometry.Objects().Append (aSet);
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())
{
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 // Process all connected OpenGL structures
for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures()); anIts.More(); anIts.Next()) for (OpenGl_ListOfStructure::Iterator anIts (theStructure->ConnectedStructures()); anIts.More(); anIts.Next())
{ {
if (anIts.Value()->Transformation()->mat != NULL) 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 i = 0; i < 4; ++i)
for (Standard_Integer j = 0; j < 4; ++j) 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 // purpose : Adds OpenGL primitive array to ray-traced scene geometry
// ======================================================================= // =======================================================================
OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray ( 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 && CALL_DEF_PARRAY* aPArray = theArray->PArray();
theArray->type != TelTrianglesArrayType &&
theArray->type != TelQuadranglesArrayType && if (aPArray->type != TelPolygonsArrayType &&
theArray->type != TelTriangleFansArrayType && aPArray->type != TelTrianglesArrayType &&
theArray->type != TelTriangleStripsArrayType && aPArray->type != TelQuadranglesArrayType &&
theArray->type != TelQuadrangleStripsArrayType) aPArray->type != TelTriangleFansArrayType &&
aPArray->type != TelTriangleStripsArrayType &&
aPArray->type != TelQuadrangleStripsArrayType)
{ {
return NULL; return NULL;
} }
if (theArray->vertices == NULL) if (aPArray->vertices == NULL)
return NULL; return NULL;
#ifdef RAY_TRACE_PRINT_INFO #ifdef RAY_TRACE_PRINT_INFO
switch (theArray->type) switch (aPArray->type)
{ {
case TelPolygonsArrayType: case TelPolygonsArrayType:
std::cout << "\tAdding TelPolygonsArrayType" << std::endl; break; std::cout << "\tAdding TelPolygonsArrayType" << std::endl; break;
@ -398,16 +488,16 @@ OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (
} }
#endif #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], BVH_Vec4f aVertex (aPArray->vertices[aVert].xyz[0],
theArray->vertices[aVert].xyz[1], aPArray->vertices[aVert].xyz[1],
theArray->vertices[aVert].xyz[2], aPArray->vertices[aVert].xyz[2],
1.f); 1.f);
if (theTransform) if (theTransform)
aVertex = MatVecMult (theTransform, aVertex); aVertex = MatVecMult (theTransform, aVertex);
@ -415,20 +505,20 @@ OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (
aSet->Vertices.push_back (aVertex); 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; BVH_Vec4f aNormal;
// Note: In case of absence of normals, the // Note: In case of absence of normals, the
// renderer uses generated geometric normals // renderer uses generated geometric normals
if (theArray->vnormals != NULL) if (aPArray->vnormals != NULL)
{ {
aNormal = BVH_Vec4f (theArray->vnormals[aNorm].xyz[0], aNormal = BVH_Vec4f (aPArray->vnormals[aNorm].xyz[0],
theArray->vnormals[aNorm].xyz[1], aPArray->vnormals[aNorm].xyz[1],
theArray->vnormals[aNorm].xyz[2], aPArray->vnormals[aNorm].xyz[2],
0.f); 0.f);
if (theTransform) if (theTransform)
@ -438,24 +528,24 @@ OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (
aSet->Normals.push_back (aNormal); aSet->Normals.push_back (aNormal);
} }
if (theArray->num_bounds > 0) if (aPArray->num_bounds > 0)
{ {
#ifdef RAY_TRACE_PRINT_INFO #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 #endif
Standard_Integer aBoundStart = 0; 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 #ifdef RAY_TRACE_PRINT_INFO
std::cout << "\tAdding indices from bound " << aBound << ": " << std::cout << "\tAdding indices from bound " << aBound << ": " <<
aBoundStart << " .. " << aVertNum << std::endl; aBoundStart << " .. " << aVertNum << std::endl;
#endif #endif
if (!AddRaytraceVertexIndices (aSet, theArray, aBoundStart, aVertNum, theMatID)) if (!AddRaytraceVertexIndices (aSet, aPArray, aBoundStart, aVertNum, theMatID))
{ {
delete aSet; delete aSet;
return NULL; return NULL;
@ -466,13 +556,13 @@ OpenGl_TriangleSet* OpenGl_Workspace::AddRaytracePrimitiveArray (
} }
else 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 #ifdef RAY_TRACE_PRINT_INFO
std::cout << "\tAdding indices from array: " << aVertNum << std::endl; std::cout << "\tAdding indices from array: " << aVertNum << std::endl;
#endif #endif
if (!AddRaytraceVertexIndices (aSet, theArray, 0, aVertNum, theMatID)) if (!AddRaytraceVertexIndices (aSet, aPArray, 0, aVertNum, theMatID))
{ {
delete aSet; delete aSet;
return NULL; return NULL;
@ -853,15 +943,14 @@ Standard_Boolean OpenGl_Workspace::UpdateRaytraceEnvironmentMap()
myView->TextureEnv()->Bind ( myView->TextureEnv()->Bind (
myGlContext, GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture); myGlContext, GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture);
aProgram->SetUniform (myGlContext, "uEnvironmentEnable", 1); aProgram->SetUniform (myGlContext,
myUniformLocations[anIdx][OpenGl_RT_uEnvironmentEnable], 1);
} }
else 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; std::cout << "Info: Rebuild shaders with stack size: " << myTraversalStackSize << std::endl;
#endif #endif
// Change state to force update all uniforms.
++myViewModificationStatus;
TCollection_AsciiString aStackSizeStr = TCollection_AsciiString aStackSizeStr =
TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myTraversalStackSize); TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myTraversalStackSize);
@ -1256,6 +1348,10 @@ Standard_Boolean OpenGl_Workspace::InitRaytraceResources()
"uRaytraceMaterialTexture", OpenGl_RT_RaytraceMaterialTexture); "uRaytraceMaterialTexture", OpenGl_RT_RaytraceMaterialTexture);
aShaderProgram->SetSampler (myGlContext, aShaderProgram->SetSampler (myGlContext,
"uRaytraceLightSrcTexture", OpenGl_RT_RaytraceLightSrcTexture); "uRaytraceLightSrcTexture", OpenGl_RT_RaytraceLightSrcTexture);
aShaderProgram->SetSampler (myGlContext,
"uSceneTransformTexture", OpenGl_RT_SceneTransformTexture);
aShaderProgram->SetSampler (myGlContext,
"uEnvironmentMapTexture", OpenGl_RT_EnvironmentMapTexture);
if (anIndex == 1) if (anIndex == 1)
{ {
@ -1304,6 +1400,9 @@ Standard_Boolean OpenGl_Workspace::InitRaytraceResources()
aShaderProgram->GetUniformLocation (myGlContext, "uOffsetY"); aShaderProgram->GetUniformLocation (myGlContext, "uOffsetY");
myUniformLocations[anIndex][OpenGl_RT_uSamples] = myUniformLocations[anIndex][OpenGl_RT_uSamples] =
aShaderProgram->GetUniformLocation (myGlContext, "uSamples"); aShaderProgram->GetUniformLocation (myGlContext, "uSamples");
myUniformLocations[anIndex][OpenGl_RT_uEnvironmentEnable] =
aShaderProgram->GetUniformLocation (myGlContext, "uEnvironmentEnable");
} }
OpenGl_ShaderProgram::Unbind (myGlContext); OpenGl_ShaderProgram::Unbind (myGlContext);
@ -1371,6 +1470,8 @@ void OpenGl_Workspace::ReleaseRaytraceResources()
NullifyResource (myGlContext, mySceneMinPointTexture); NullifyResource (myGlContext, mySceneMinPointTexture);
NullifyResource (myGlContext, mySceneMaxPointTexture); NullifyResource (myGlContext, mySceneMaxPointTexture);
NullifyResource (myGlContext, mySceneTransformTexture);
NullifyResource (myGlContext, myObjectNodeInfoTexture); NullifyResource (myGlContext, myObjectNodeInfoTexture);
NullifyResource (myGlContext, myObjectMinPointTexture); NullifyResource (myGlContext, myObjectMinPointTexture);
NullifyResource (myGlContext, myObjectMaxPointTexture); NullifyResource (myGlContext, myObjectMaxPointTexture);
@ -1408,10 +1509,12 @@ Standard_Boolean OpenGl_Workspace::UploadRaytraceData()
mySceneNodeInfoTexture = new OpenGl_TextureBufferArb; mySceneNodeInfoTexture = new OpenGl_TextureBufferArb;
mySceneMinPointTexture = new OpenGl_TextureBufferArb; mySceneMinPointTexture = new OpenGl_TextureBufferArb;
mySceneMaxPointTexture = new OpenGl_TextureBufferArb; mySceneMaxPointTexture = new OpenGl_TextureBufferArb;
mySceneTransformTexture = new OpenGl_TextureBufferArb;
if (!mySceneNodeInfoTexture->Create (myGlContext) if (!mySceneNodeInfoTexture->Create (myGlContext)
|| !mySceneMinPointTexture->Create (myGlContext) || !mySceneMinPointTexture->Create (myGlContext)
|| !mySceneMaxPointTexture->Create (myGlContext)) || !mySceneMaxPointTexture->Create (myGlContext)
|| !mySceneTransformTexture->Create (myGlContext))
{ {
#ifdef RAY_TRACE_PRINT_INFO #ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to create buffers for high-level scene BVH" << std::endl; 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; 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 aTotalVerticesNb = 0;
Standard_Size aTotalElementsNb = 0; Standard_Size aTotalElementsNb = 0;
Standard_Size aTotalBVHNodesNb = 0; Standard_Size aTotalBVHNodesNb = 0;
@ -1658,6 +1789,9 @@ Standard_Boolean OpenGl_Workspace::UploadRaytraceData()
aMemUsed += static_cast<Standard_ShortReal> ( aMemUsed += static_cast<Standard_ShortReal> (
myRaytraceGeometry.BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec4f)); 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; std::cout << "GPU Memory Used (MB): ~" << aMemUsed / 1048576 << std::endl;
#endif #endif
@ -1764,6 +1898,7 @@ Standard_Boolean OpenGl_Workspace::RunRaytraceShaders (const Graphic3d_CView& th
myGeometryTriangTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture); myGeometryTriangTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture);
myRaytraceMaterialTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture); myRaytraceMaterialTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture);
myRaytraceLightSrcTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture); myRaytraceLightSrcTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture);
mySceneTransformTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneTransformTexture);
if (theCView.IsAntialiasingEnabled) // render source image to FBO 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); myUniformLocations[1][OpenGl_RT_aPosition], 3, GL_FLOAT, GL_FALSE, 0, NULL);
// Perform multi-pass adaptive FSAA using ping-pong technique // Perform multi-pass adaptive FSAA using ping-pong technique
// rotated grid AA always uses 4 samples
for (Standard_Integer anIt = 0; anIt < 4; ++anIt) for (Standard_Integer anIt = 0; anIt < 4; ++anIt)
{ {
GLfloat aOffsetX = 1.f / theSizeX; GLfloat aOffsetX = 1.f / theSizeX;
@ -1934,7 +2070,7 @@ Standard_Boolean OpenGl_Workspace::Raytrace (const Graphic3d_CView& theCView,
const Standard_Boolean theToSwap, const Standard_Boolean theToSwap,
OpenGl_FrameBuffer* theFrameBuffer) OpenGl_FrameBuffer* theFrameBuffer)
{ {
if (!UpdateRaytraceGeometry (Standard_True)) if (!UpdateRaytraceGeometry (OpenGl_GUM_CHECK))
return Standard_False; return Standard_False;
if (!InitRaytraceResources()) if (!InitRaytraceResources())
@ -1978,11 +2114,8 @@ Standard_Boolean OpenGl_Workspace::Raytrace (const Graphic3d_CView& theCView,
aOrigins, aOrigins,
aDirects); aDirects);
// Draw background Standard_Boolean wasBlendingEnabled = glIsEnabled (GL_BLEND);
glPushAttrib (GL_ENABLE_BIT | Standard_Boolean wasDepthTestEnabled = glIsEnabled (GL_DEPTH_TEST);
GL_CURRENT_BIT |
GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT);
glDisable (GL_DEPTH_TEST); glDisable (GL_DEPTH_TEST);
@ -2029,10 +2162,11 @@ Standard_Boolean OpenGl_Workspace::Raytrace (const Graphic3d_CView& theCView,
myRaytraceScreenQuad.Unbind (myGlContext); myRaytraceScreenQuad.Unbind (myGlContext);
} }
if (theFrameBuffer != NULL) if (!wasBlendingEnabled)
theFrameBuffer->UnbindBuffer (myGlContext); glDisable (GL_BLEND);
glPopAttrib(); if (wasDepthTestEnabled)
glEnable (GL_DEPTH_TEST);
// Swap the buffers // Swap the buffers
if (theToSwap) if (theToSwap)

View File

@ -25,6 +25,8 @@ uniform isamplerBuffer uSceneNodeInfoTexture;
uniform samplerBuffer uSceneMinPointTexture; uniform samplerBuffer uSceneMinPointTexture;
//! Texture buffer of maximum points of high-level BVH nodes. //! Texture buffer of maximum points of high-level BVH nodes.
uniform samplerBuffer uSceneMaxPointTexture; 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. //! Texture buffer of data records of bottom-level BVH nodes.
uniform isamplerBuffer uObjectNodeInfoTexture; uniform isamplerBuffer uObjectNodeInfoTexture;
@ -99,6 +101,38 @@ struct SIntersect
#define AXIS_Y vec3 (0.f, 1.f, 0.f) #define AXIS_Y vec3 (0.f, 1.f, 0.f)
#define AXIS_Z vec3 (0.f, 0.f, 1.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 // Functions for compute ray-object intersection
@ -171,12 +205,12 @@ float IntersectTriangle (in SRay theRay,
int(theUV.x + theUV.y <= 1.f)) ? aTime : MAXFLOAT; int(theUV.x + theUV.y <= 1.f)) ? aTime : MAXFLOAT;
} }
//! Global stack shared between traversal functions.
int Stack[STACK_SIZE];
//! Identifies the absence of intersection. //! Identifies the absence of intersection.
#define INALID_HIT ivec4 (-1) #define INALID_HIT ivec4 (-1)
//! Global stack shared between traversal functions.
int Stack[STACK_SIZE];
// ======================================================================= // =======================================================================
// function : ObjectNearestHit // function : ObjectNearestHit
// purpose : Finds intersection with nearest object triangle // purpose : Finds intersection with nearest object triangle
@ -391,7 +425,7 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
// function : SceneNearestHit // function : SceneNearestHit
// purpose : Finds intersection with nearest scene triangle // 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 aHead = -1; // stack pointer
int aNode = 0; // node to visit 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) 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 ( 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) 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.y + aData.z, // vertex 1
aTriIndex.z + aData.z, // vertex 2 aTriIndex.z + aData.z, // vertex 2
aTriIndex.w); // material 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 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 ( 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) if (aHead < 0 || isShadow)
return isShadow ? 0.f : 1.f; return isShadow ? 0.f : 1.f;
@ -625,11 +703,13 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
vec3 aResult = vec3 (0.f); vec3 aResult = vec3 (0.f);
vec4 aWeight = vec4 (1.f); vec4 aWeight = vec4 (1.f);
int anObjectId;
for (int aDepth = 0; aDepth < 5; ++aDepth) for (int aDepth = 0; aDepth < 5; ++aDepth)
{ {
SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO); SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit); ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
if (aTriIndex.x == -1) if (aTriIndex.x == -1)
{ {
@ -668,6 +748,14 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex); 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); aHit.Normal = normalize (aHit.Normal);
for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx) for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)