1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00
occt/src/OpenGl/OpenGl_Workspace_Raytrace.cxx
dbp fc73a20256 0024739: TKOpenGl - port ray-tracing from OpenCL to GLSL for better integration and portability
RayTracing - disable reflections by default
Fix possible compilation issue on Mac OS X.
2014-04-04 14:15:08 +04:00

2074 lines
72 KiB
C++
Executable File

// Created on: 2013-08-27
// Created by: Denis BOGOLEPOV
// Copyright (c) 2013 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <NCollection_Mat4.hxx>
#include <OpenGl_ArbFBO.hxx>
#include <OpenGl_FrameBuffer.hxx>
#include <OpenGl_Texture.hxx>
#include <OpenGl_VertexBuffer.hxx>
#include <OpenGl_View.hxx>
#include <OpenGl_Workspace.hxx>
#include <OSD_File.hxx>
#include <OSD_Protection.hxx>
#include <Standard_Assert.hxx>
using namespace OpenGl_Raytrace;
//! Use this macro to output ray-tracing debug info
// #define RAY_TRACE_PRINT_INFO
#ifdef RAY_TRACE_PRINT_INFO
#include <OSD_Timer.hxx>
#endif
// =======================================================================
// function : MatVecMult
// purpose : Multiples 4x4 matrix by 4D vector
// =======================================================================
template<typename T>
BVH_Vec4f MatVecMult (const T m[16], const BVH_Vec4f& v)
{
return BVH_Vec4f (
static_cast<float> (m[ 0] * v.x() + m[ 4] * v.y() +
m[ 8] * v.z() + m[12] * v.w()),
static_cast<float> (m[ 1] * v.x() + m[ 5] * v.y() +
m[ 9] * v.z() + m[13] * v.w()),
static_cast<float> (m[ 2] * v.x() + m[ 6] * v.y() +
m[10] * v.z() + m[14] * v.w()),
static_cast<float> (m[ 3] * v.x() + m[ 7] * v.y() +
m[11] * v.z() + m[15] * v.w()));
}
// =======================================================================
// function : UpdateRaytraceGeometry
// purpose : Updates 3D scene geometry for ray tracing
// =======================================================================
Standard_Boolean OpenGl_Workspace::UpdateRaytraceGeometry (Standard_Boolean theCheck)
{
if (myView.IsNull())
return Standard_False;
// Note: In 'check' mode the scene geometry is analyzed for modifications
// This is light-weight procedure performed for each frame
if (!theCheck)
{
myRaytraceGeometry.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;
const OpenGl_LayerList& aList = myView->LayerList();
for (OpenGl_SequenceOfLayers::Iterator anLayerIt (aList.Layers()); anLayerIt.More(); anLayerIt.Next())
{
const OpenGl_PriorityList& aPriorityList = anLayerIt.Value();
if (aPriorityList.NbStructures() == 0)
continue;
const OpenGl_ArrayOfStructure& aStructArray = aPriorityList.ArrayOfStructures();
for (Standard_Integer anIndex = 0; anIndex < aStructArray.Length(); ++anIndex)
{
OpenGl_SequenceOfStructure::Iterator aStructIt;
for (aStructIt.Init (aStructArray (anIndex)); aStructIt.More(); aStructIt.Next())
{
const OpenGl_Structure* aStructure = aStructIt.Value();
if (theCheck)
{
if (CheckRaytraceStructure (aStructure))
{
return UpdateRaytraceGeometry (Standard_False);
}
}
else
{
if (!aStructure->IsRaytracable())
continue;
if (aStructure->Transformation()->mat != NULL)
{
if (aTransform == NULL)
aTransform = new Standard_ShortReal[16];
for (Standard_Integer i = 0; i < 4; ++i)
for (Standard_Integer j = 0; j < 4; ++j)
{
aTransform[j * 4 + i] = aStructure->Transformation()->mat[i][j];
}
}
AddRaytraceStructure (aStructure, aTransform, anElements);
}
}
}
}
if (!theCheck)
{
// Actualize the hash map of structures -- remove out-of-date records
std::map<const OpenGl_Structure*, Standard_Size>::iterator anIter = myStructureStates.begin();
while (anIter != myStructureStates.end())
{
if (anElements.find (anIter->first) == anElements.end())
{
myStructureStates.erase (anIter++);
}
else
{
++anIter;
}
}
// Actualize OpenGL layer list state
myLayersModificationStatus = myView->LayerList().ModificationState();
// Rebuild bottom-level and high-level BVHs
myRaytraceGeometry.ProcessAcceleration();
const Standard_ShortReal aMinRadius = Max (fabs (myRaytraceGeometry.Box().CornerMin().x()), Max (
fabs (myRaytraceGeometry.Box().CornerMin().y()), fabs (myRaytraceGeometry.Box().CornerMin().z())));
const Standard_ShortReal aMaxRadius = Max (fabs (myRaytraceGeometry.Box().CornerMax().x()), Max (
fabs (myRaytraceGeometry.Box().CornerMax().y()), fabs (myRaytraceGeometry.Box().CornerMax().z())));
myRaytraceSceneRadius = 2.f /* scale factor */ * Max (aMinRadius, aMaxRadius);
const BVH_Vec4f aSize = myRaytraceGeometry.Box().Size();
myRaytraceSceneEpsilon = Max (1e-4f, 1e-4f * sqrtf (
aSize.x() * aSize.x() + aSize.y() * aSize.y() + aSize.z() * aSize.z()));
return UploadRaytraceData();
}
delete [] aTransform;
return Standard_True;
}
// =======================================================================
// function : CheckRaytraceStructure
// purpose : Checks to see if the structure is modified
// =======================================================================
Standard_Boolean OpenGl_Workspace::CheckRaytraceStructure (const OpenGl_Structure* theStructure)
{
if (!theStructure->IsRaytracable())
{
// Checks to see if all ray-tracable elements were
// removed from the structure
if (theStructure->ModificationState() > 0)
{
theStructure->ResetModificationState();
return Standard_True;
}
return Standard_False;
}
std::map<const OpenGl_Structure*, Standard_Size>::iterator aStructState = myStructureStates.find (theStructure);
if (aStructState != myStructureStates.end())
return aStructState->second != theStructure->ModificationState();
return Standard_True;
}
// =======================================================================
// function : CreateMaterial
// purpose : Creates ray-tracing material properties
// =======================================================================
void CreateMaterial (const OPENGL_SURF_PROP& theProp, OpenGl_RaytraceMaterial& theMaterial)
{
const float* aSrcAmb = theProp.isphysic ? theProp.ambcol.rgb : theProp.matcol.rgb;
theMaterial.Ambient = BVH_Vec4f (aSrcAmb[0] * theProp.amb,
aSrcAmb[1] * theProp.amb,
aSrcAmb[2] * theProp.amb,
1.0f);
const float* aSrcDif = theProp.isphysic ? theProp.difcol.rgb : theProp.matcol.rgb;
theMaterial.Diffuse = BVH_Vec4f (aSrcDif[0] * theProp.diff,
aSrcDif[1] * theProp.diff,
aSrcDif[2] * theProp.diff,
1.0f);
const float aDefSpecCol[4] = {1.0f, 1.0f, 1.0f, 1.0f};
const float* aSrcSpe = theProp.isphysic ? theProp.speccol.rgb : aDefSpecCol;
theMaterial.Specular = BVH_Vec4f (aSrcSpe[0] * theProp.spec,
aSrcSpe[1] * theProp.spec,
aSrcSpe[2] * theProp.spec,
theProp.shine);
const float* aSrcEms = theProp.isphysic ? theProp.emscol.rgb : theProp.matcol.rgb;
theMaterial.Emission = BVH_Vec4f (aSrcEms[0] * theProp.emsv,
aSrcEms[1] * theProp.emsv,
aSrcEms[2] * theProp.emsv,
1.0f);
// Note: Here we use sub-linear transparency function
// to produce realistic-looking transparency effect
theMaterial.Transparency = BVH_Vec4f (powf (theProp.trans, 0.75f),
1.f - theProp.trans,
1.f,
1.f);
const float aMaxRefl = Max (theMaterial.Diffuse.x() + theMaterial.Specular.x(),
Max (theMaterial.Diffuse.y() + theMaterial.Specular.y(),
theMaterial.Diffuse.z() + theMaterial.Specular.z()));
const float aReflectionScale = 0.75f / aMaxRefl;
theMaterial.Reflection = BVH_Vec4f (theProp.speccol.rgb[0] * theProp.spec * aReflectionScale,
theProp.speccol.rgb[1] * theProp.spec * aReflectionScale,
theProp.speccol.rgb[2] * theProp.spec * aReflectionScale,
0.f);
}
// =======================================================================
// function : AddRaytraceStructure
// purpose : Adds OpenGL structure to ray-traced scene geometry
// =======================================================================
Standard_Boolean OpenGl_Workspace::AddRaytraceStructure (const OpenGl_Structure* theStructure,
const Standard_ShortReal* theTransform, std::set<const OpenGl_Structure*>& theElements)
{
theElements.insert (theStructure);
if (!theStructure->IsVisible())
{
myStructureStates[theStructure] = theStructure->ModificationState();
return Standard_True;
}
// Get structure material
Standard_Integer aStructMatID = -1;
if (theStructure->AspectFace() != NULL)
{
aStructMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
OpenGl_RaytraceMaterial aStructMaterial;
CreateMaterial (theStructure->AspectFace()->IntFront(), aStructMaterial);
myRaytraceGeometry.Materials.push_back (aStructMaterial);
}
for (OpenGl_Structure::GroupIterator aGroupIter (theStructure->DrawGroups()); aGroupIter.More(); aGroupIter.Next())
{
// Get group material
Standard_Integer aGroupMatID = -1;
if (aGroupIter.Value()->AspectFace() != NULL)
{
aGroupMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
OpenGl_RaytraceMaterial aGroupMaterial;
CreateMaterial (aGroupIter.Value()->AspectFace()->IntFront(), aGroupMaterial);
myRaytraceGeometry.Materials.push_back (aGroupMaterial);
}
Standard_Integer aMatID = aGroupMatID < 0 ? aStructMatID : aGroupMatID;
if (aMatID < 0)
{
aMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
myRaytraceGeometry.Materials.push_back (OpenGl_RaytraceMaterial());
}
// Add OpenGL elements from group (extract primitives arrays and aspects)
for (const OpenGl_ElementNode* aNode = aGroupIter.Value()->FirstNode(); aNode != NULL; aNode = aNode->next)
{
OpenGl_AspectFace* anAspect = dynamic_cast<OpenGl_AspectFace*> (aNode->elem);
if (anAspect != NULL)
{
aMatID = static_cast<Standard_Integer> (myRaytraceGeometry.Materials.size());
OpenGl_RaytraceMaterial aMaterial;
CreateMaterial (anAspect->IntFront(), aMaterial);
myRaytraceGeometry.Materials.push_back (aMaterial);
}
else
{
OpenGl_PrimitiveArray* aPrimArray = dynamic_cast<OpenGl_PrimitiveArray*> (aNode->elem);
if (aPrimArray != NULL)
{
NCollection_Handle<BVH_Object<Standard_ShortReal, 4> > aSet =
AddRaytracePrimitiveArray (aPrimArray->PArray(), aMatID, theTransform);
if (!aSet.IsNull())
myRaytraceGeometry.Objects().Append (aSet);
}
}
}
}
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];
for (Standard_Integer i = 0; i < 4; ++i)
for (Standard_Integer j = 0; j < 4; ++j)
{
aTransform[j * 4 + i] =
anIts.Value()->Transformation()->mat[i][j];
}
}
if (anIts.Value()->IsRaytracable())
AddRaytraceStructure (anIts.Value(), aTransform != NULL ? aTransform : theTransform, theElements);
}
delete[] aTransform;
myStructureStates[theStructure] = theStructure->ModificationState();
return Standard_True;
}
// =======================================================================
// function : AddRaytracePrimitiveArray
// 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)
{
if (theArray->type != TelPolygonsArrayType &&
theArray->type != TelTrianglesArrayType &&
theArray->type != TelQuadranglesArrayType &&
theArray->type != TelTriangleFansArrayType &&
theArray->type != TelTriangleStripsArrayType &&
theArray->type != TelQuadrangleStripsArrayType)
{
return NULL;
}
if (theArray->vertices == NULL)
return NULL;
#ifdef RAY_TRACE_PRINT_INFO
switch (theArray->type)
{
case TelPolygonsArrayType:
std::cout << "\tAdding TelPolygonsArrayType" << std::endl; break;
case TelTrianglesArrayType:
std::cout << "\tAdding TelTrianglesArrayType" << std::endl; break;
case TelQuadranglesArrayType:
std::cout << "\tAdding TelQuadranglesArrayType" << std::endl; break;
case TelTriangleFansArrayType:
std::cout << "\tAdding TelTriangleFansArrayType" << std::endl; break;
case TelTriangleStripsArrayType:
std::cout << "\tAdding TelTriangleStripsArrayType" << std::endl; break;
case TelQuadrangleStripsArrayType:
std::cout << "\tAdding TelQuadrangleStripsArrayType" << std::endl; break;
}
#endif
OpenGl_TriangleSet* aSet = new OpenGl_TriangleSet;
{
aSet->Vertices.reserve (theArray->num_vertexs);
for (Standard_Integer aVert = 0; aVert < theArray->num_vertexs; ++aVert)
{
BVH_Vec4f aVertex (theArray->vertices[aVert].xyz[0],
theArray->vertices[aVert].xyz[1],
theArray->vertices[aVert].xyz[2],
1.f);
if (theTransform)
aVertex = MatVecMult (theTransform, aVertex);
aSet->Vertices.push_back (aVertex);
}
aSet->Normals.reserve (theArray->num_vertexs);
for (Standard_Integer aNorm = 0; aNorm < theArray->num_vertexs; ++aNorm)
{
BVH_Vec4f aNormal;
// Note: In case of absence of normals, the
// renderer uses generated geometric normals
if (theArray->vnormals != NULL)
{
aNormal = BVH_Vec4f (theArray->vnormals[aNorm].xyz[0],
theArray->vnormals[aNorm].xyz[1],
theArray->vnormals[aNorm].xyz[2],
0.f);
if (theTransform)
aNormal = MatVecMult (theTransform, aNormal);
}
aSet->Normals.push_back (aNormal);
}
if (theArray->num_bounds > 0)
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "\tNumber of bounds = " << theArray->num_bounds << std::endl;
#endif
Standard_Integer aBoundStart = 0;
for (Standard_Integer aBound = 0; aBound < theArray->num_bounds; ++aBound)
{
const Standard_Integer aVertNum = theArray->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))
{
delete aSet;
return NULL;
}
aBoundStart += aVertNum;
}
}
else
{
const Standard_Integer aVertNum = theArray->num_edges > 0 ? theArray->num_edges : theArray->num_vertexs;
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "\tAdding indices from array: " << aVertNum << std::endl;
#endif
if (!AddRaytraceVertexIndices (aSet, theArray, 0, aVertNum, theMatID))
{
delete aSet;
return NULL;
}
}
}
if (aSet->Size() != 0)
aSet->MarkDirty();
return aSet;
}
// =======================================================================
// function : AddRaytraceVertexIndices
// purpose : Adds vertex indices to ray-traced scene geometry
// =======================================================================
Standard_Boolean OpenGl_Workspace::AddRaytraceVertexIndices (OpenGl_TriangleSet* theSet,
const CALL_DEF_PARRAY* theArray, Standard_Integer theOffset, Standard_Integer theCount, Standard_Integer theMatID)
{
switch (theArray->type)
{
case TelTrianglesArrayType:
return AddRaytraceTriangleArray (theSet, theArray, theOffset, theCount, theMatID);
case TelQuadranglesArrayType:
return AddRaytraceQuadrangleArray (theSet, theArray, theOffset, theCount, theMatID);
case TelTriangleFansArrayType:
return AddRaytraceTriangleFanArray (theSet, theArray, theOffset, theCount, theMatID);
case TelTriangleStripsArrayType:
return AddRaytraceTriangleStripArray (theSet, theArray, theOffset, theCount, theMatID);
case TelQuadrangleStripsArrayType:
return AddRaytraceQuadrangleStripArray (theSet, theArray, theOffset, theCount, theMatID);
default:
return AddRaytracePolygonArray (theSet, theArray, theOffset, theCount, theMatID);
}
}
// =======================================================================
// function : AddRaytraceTriangleArray
// purpose : Adds OpenGL triangle array to ray-traced scene geometry
// =======================================================================
Standard_Boolean OpenGl_Workspace::AddRaytraceTriangleArray (OpenGl_TriangleSet* theSet,
const CALL_DEF_PARRAY* theArray, Standard_Integer theOffset, Standard_Integer theCount, Standard_Integer theMatID)
{
if (theCount < 3)
return Standard_True;
theSet->Elements.reserve (theSet->Elements.size() + theCount / 3);
if (theArray->num_edges > 0)
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; aVert += 3)
{
theSet->Elements.push_back (BVH_Vec4i (theArray->edges[aVert + 0],
theArray->edges[aVert + 1],
theArray->edges[aVert + 2],
theMatID));
}
}
else
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; aVert += 3)
{
theSet->Elements.push_back (BVH_Vec4i (aVert + 0,
aVert + 1,
aVert + 2,
theMatID));
}
}
return Standard_True;
}
// =======================================================================
// function : AddRaytraceTriangleFanArray
// purpose : Adds OpenGL triangle fan array to ray-traced scene geometry
// =======================================================================
Standard_Boolean OpenGl_Workspace::AddRaytraceTriangleFanArray (OpenGl_TriangleSet* theSet,
const CALL_DEF_PARRAY* theArray, Standard_Integer theOffset, Standard_Integer theCount, Standard_Integer theMatID)
{
if (theCount < 3)
return Standard_True;
theSet->Elements.reserve (theSet->Elements.size() + theCount - 2);
if (theArray->num_edges > 0)
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert)
{
theSet->Elements.push_back (BVH_Vec4i (theArray->edges[theOffset],
theArray->edges[aVert + 1],
theArray->edges[aVert + 2],
theMatID));
}
}
else
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert)
{
theSet->Elements.push_back (BVH_Vec4i (theOffset,
aVert + 1,
aVert + 2,
theMatID));
}
}
return Standard_True;
}
// =======================================================================
// function : AddRaytraceTriangleStripArray
// purpose : Adds OpenGL triangle strip array to ray-traced scene geometry
// =======================================================================
Standard_Boolean OpenGl_Workspace::AddRaytraceTriangleStripArray (OpenGl_TriangleSet* theSet,
const CALL_DEF_PARRAY* theArray, Standard_Integer theOffset, Standard_Integer theCount, Standard_Integer theMatID)
{
if (theCount < 3)
return Standard_True;
theSet->Elements.reserve (theSet->Elements.size() + theCount - 2);
if (theArray->num_edges > 0)
{
for (Standard_Integer aVert = theOffset, aCW = 0; aVert < theOffset + theCount - 2; ++aVert, aCW = (aCW + 1) % 2)
{
theSet->Elements.push_back (BVH_Vec4i (theArray->edges[aVert + aCW ? 1 : 0],
theArray->edges[aVert + aCW ? 0 : 1],
theArray->edges[aVert + 2],
theMatID));
}
}
else
{
for (Standard_Integer aVert = theOffset, aCW = 0; aVert < theOffset + theCount - 2; ++aVert, aCW = (aCW + 1) % 2)
{
theSet->Elements.push_back (BVH_Vec4i (aVert + aCW ? 1 : 0,
aVert + aCW ? 0 : 1,
aVert + 2,
theMatID));
}
}
return Standard_True;
}
// =======================================================================
// function : AddRaytraceQuadrangleArray
// purpose : Adds OpenGL quad array to ray-traced scene geometry
// =======================================================================
Standard_Boolean OpenGl_Workspace::AddRaytraceQuadrangleArray (OpenGl_TriangleSet* theSet,
const CALL_DEF_PARRAY* theArray, Standard_Integer theOffset, Standard_Integer theCount, Standard_Integer theMatID)
{
if (theCount < 4)
return Standard_True;
theSet->Elements.reserve (theSet->Elements.size() + theCount / 2);
if (theArray->num_edges > 0)
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 4)
{
theSet->Elements.push_back (BVH_Vec4i (theArray->edges[aVert + 0],
theArray->edges[aVert + 1],
theArray->edges[aVert + 2],
theMatID));
theSet->Elements.push_back (BVH_Vec4i (theArray->edges[aVert + 0],
theArray->edges[aVert + 2],
theArray->edges[aVert + 3],
theMatID));
}
}
else
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 4)
{
theSet->Elements.push_back (BVH_Vec4i (aVert + 0,
aVert + 1,
aVert + 2,
theMatID));
theSet->Elements.push_back (BVH_Vec4i (aVert + 0,
aVert + 2,
aVert + 3,
theMatID));
}
}
return Standard_True;
}
// =======================================================================
// function : AddRaytraceQuadrangleStripArray
// purpose : Adds OpenGL quad strip array to ray-traced scene geometry
// =======================================================================
Standard_Boolean OpenGl_Workspace::AddRaytraceQuadrangleStripArray (OpenGl_TriangleSet* theSet,
const CALL_DEF_PARRAY* theArray, Standard_Integer theOffset, Standard_Integer theCount, Standard_Integer theMatID)
{
if (theCount < 4)
return Standard_True;
theSet->Elements.reserve (theSet->Elements.size() + 2 * theCount - 6);
if (theArray->num_edges > 0)
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 2)
{
theSet->Elements.push_back (BVH_Vec4i (theArray->edges[aVert + 0],
theArray->edges[aVert + 1],
theArray->edges[aVert + 2],
theMatID));
theSet->Elements.push_back (BVH_Vec4i (theArray->edges[aVert + 1],
theArray->edges[aVert + 3],
theArray->edges[aVert + 2],
theMatID));
}
}
else
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 3; aVert += 2)
{
theSet->Elements.push_back (BVH_Vec4i (aVert + 0,
aVert + 1,
aVert + 2,
theMatID));
theSet->Elements.push_back (BVH_Vec4i (aVert + 1,
aVert + 3,
aVert + 2,
theMatID));
}
}
return Standard_True;
}
// =======================================================================
// function : AddRaytracePolygonArray
// purpose : Adds OpenGL polygon array to ray-traced scene geometry
// =======================================================================
Standard_Boolean OpenGl_Workspace::AddRaytracePolygonArray (OpenGl_TriangleSet* theSet,
const CALL_DEF_PARRAY* theArray, Standard_Integer theOffset, Standard_Integer theCount, Standard_Integer theMatID)
{
if (theCount < 3)
return Standard_True;
theSet->Elements.reserve (theSet->Elements.size() + theCount - 2);
if (theArray->num_edges > 0)
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert)
{
theSet->Elements.push_back (BVH_Vec4i (theArray->edges[theOffset],
theArray->edges[aVert + 1],
theArray->edges[aVert + 2],
theMatID));
}
}
else
{
for (Standard_Integer aVert = theOffset; aVert < theOffset + theCount - 2; ++aVert)
{
theSet->Elements.push_back (BVH_Vec4i (theOffset,
aVert + 1,
aVert + 2,
theMatID));
}
}
return Standard_True;
}
// =======================================================================
// function : UpdateRaytraceLightSources
// purpose : Updates 3D scene light sources for ray-tracing
// =======================================================================
Standard_Boolean OpenGl_Workspace::UpdateRaytraceLightSources (const GLdouble theInvModelView[16])
{
myRaytraceGeometry.Sources.clear();
myRaytraceGeometry.Ambient = BVH_Vec4f (0.0f, 0.0f, 0.0f, 0.0f);
for (OpenGl_ListOfLight::Iterator anItl (myView->LightList()); anItl.More(); anItl.Next())
{
const OpenGl_Light& aLight = anItl.Value();
if (aLight.Type == Visual3d_TOLS_AMBIENT)
{
myRaytraceGeometry.Ambient += BVH_Vec4f (aLight.Color.r(),
aLight.Color.g(),
aLight.Color.b(),
0.0f);
continue;
}
BVH_Vec4f aDiffuse (aLight.Color.r(),
aLight.Color.g(),
aLight.Color.b(),
1.0f);
BVH_Vec4f aPosition (-aLight.Direction.x(),
-aLight.Direction.y(),
-aLight.Direction.z(),
0.0f);
if (aLight.Type != Visual3d_TOLS_DIRECTIONAL)
{
aPosition = BVH_Vec4f (aLight.Position.x(),
aLight.Position.y(),
aLight.Position.z(),
1.0f);
}
if (aLight.IsHeadlight)
aPosition = MatVecMult (theInvModelView, aPosition);
myRaytraceGeometry.Sources.push_back (OpenGl_RaytraceLight (aDiffuse, aPosition));
}
if (myRaytraceLightSrcTexture.IsNull()) // create light source buffer
{
myRaytraceLightSrcTexture = new OpenGl_TextureBufferArb;
if (!myRaytraceLightSrcTexture->Create (myGlContext))
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to create light source buffer" << std::endl;
#endif
return Standard_False;
}
}
if (myRaytraceGeometry.Sources.size() != 0)
{
const GLfloat* aDataPtr = myRaytraceGeometry.Sources.front().Packed();
bool aResult = myRaytraceLightSrcTexture->Init (
myGlContext, 4, myRaytraceGeometry.Sources.size() * 2, aDataPtr);
if (!aResult)
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to upload light source buffer" << std::endl;
#endif
return Standard_False;
}
}
return Standard_True;
}
// =======================================================================
// function : UpdateRaytraceEnvironmentMap
// purpose : Updates environment map for ray-tracing
// =======================================================================
Standard_Boolean OpenGl_Workspace::UpdateRaytraceEnvironmentMap()
{
if (myView.IsNull())
return Standard_False;
if (myViewModificationStatus == myView->ModificationState())
return Standard_True;
for (Standard_Integer anIdx = 0; anIdx < 2; ++anIdx)
{
const Handle(OpenGl_ShaderProgram)& aProgram =
anIdx == 0 ? myRaytraceProgram : myPostFSAAProgram;
if (!aProgram.IsNull())
{
aProgram->Bind (myGlContext);
if (!myView->TextureEnv().IsNull() && myView->SurfaceDetail() != Visual3d_TOD_NONE)
{
myView->TextureEnv()->Bind (
myGlContext, GL_TEXTURE0 + OpenGl_RT_EnvironmentMapTexture);
aProgram->SetUniform (myGlContext, "uEnvironmentEnable", 1);
}
else
{
aProgram->SetUniform (myGlContext, "uEnvironmentEnable", 0);
}
aProgram->SetSampler (myGlContext,
"uEnvironmentMapTexture", OpenGl_RT_EnvironmentMapTexture);
}
}
OpenGl_ShaderProgram::Unbind (myGlContext);
myViewModificationStatus = myView->ModificationState();
return Standard_True;
}
// =======================================================================
// function : Source
// purpose : Returns shader source combined with prefix
// =======================================================================
TCollection_AsciiString OpenGl_Workspace::ShaderSource::Source() const
{
static const TCollection_AsciiString aVersion = "#version 140";
if (myPrefix.IsEmpty())
{
return aVersion + "\n" + mySource;
}
return aVersion + "\n" + myPrefix + "\n" + mySource;
}
// =======================================================================
// function : Load
// purpose : Loads shader source from specified files
// =======================================================================
void OpenGl_Workspace::ShaderSource::Load (
const TCollection_AsciiString* theFileNames, const Standard_Integer theCount)
{
mySource.Clear();
for (Standard_Integer anIndex = 0; anIndex < theCount; ++anIndex)
{
OSD_File aFile (theFileNames[anIndex]);
Standard_ASSERT_RETURN (aFile.Exists(),
"Error: Failed to find shader source file", /* none */);
aFile.Open (OSD_ReadOnly, OSD_Protection());
TCollection_AsciiString aSource;
Standard_ASSERT_RETURN (aFile.IsOpen(),
"Error: Failed to open shader source file", /* none */);
aFile.Read (aSource, (Standard_Integer) aFile.Size());
if (!aSource.IsEmpty())
{
mySource += TCollection_AsciiString ("\n") + aSource;
}
aFile.Close();
}
}
// =======================================================================
// function : LoadShader
// purpose : Creates new shader object with specified source
// =======================================================================
Handle(OpenGl_ShaderObject) OpenGl_Workspace::LoadShader (const ShaderSource& theSource, GLenum theType)
{
Handle(OpenGl_ShaderObject) aShader = new OpenGl_ShaderObject (theType);
if (!aShader->Create (myGlContext))
{
const TCollection_ExtendedString aMessage = "Error: Failed to create shader object";
myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
aShader->Release (myGlContext.operator->());
return Handle(OpenGl_ShaderObject)();
}
if (!aShader->LoadSource (myGlContext, theSource.Source()))
{
const TCollection_ExtendedString aMessage = "Error: Failed to set shader source";
myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
aShader->Release (myGlContext.operator->());
return Handle(OpenGl_ShaderObject)();
}
TCollection_AsciiString aBuildLog;
if (!aShader->Compile (myGlContext))
{
if (aShader->FetchInfoLog (myGlContext, aBuildLog))
{
const TCollection_ExtendedString aMessage =
TCollection_ExtendedString ("Error: Failed to compile shader object:\n") + aBuildLog;
#ifdef RAY_TRACE_PRINT_INFO
std::cout << aBuildLog << std::endl;
#endif
myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
}
aShader->Release (myGlContext.operator->());
return Handle(OpenGl_ShaderObject)();
}
#ifdef RAY_TRACE_PRINT_INFO
if (aShader->FetchInfoLog (myGlContext, aBuildLog))
{
if (!aBuildLog.IsEmpty())
{
std::cout << aBuildLog << std::endl;
}
else
{
std::cout << "Info: shader build log is empty" << std::endl;
}
}
#endif
return aShader;
}
// =======================================================================
// function : SafeFailBack
// purpose : Performs safe exit when shaders initialization fails
// =======================================================================
Standard_Boolean OpenGl_Workspace::SafeFailBack (const TCollection_ExtendedString& theMessage)
{
myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, theMessage);
myComputeInitStatus = OpenGl_RT_FAIL;
ReleaseRaytraceResources();
return Standard_False;
}
// =======================================================================
// function : InitRaytraceResources
// purpose : Initializes OpenGL/GLSL shader programs
// =======================================================================
Standard_Boolean OpenGl_Workspace::InitRaytraceResources()
{
Standard_Boolean aToRebuildShaders = Standard_False;
if (myComputeInitStatus == OpenGl_RT_INIT)
{
if (!myIsRaytraceDataValid)
return Standard_True;
const Standard_Integer aRequiredStackSize =
myRaytraceGeometry.HighLevelTreeDepth() + myRaytraceGeometry.BottomLevelTreeDepth();
if (myTraversalStackSize < aRequiredStackSize)
{
myTraversalStackSize = Max (aRequiredStackSize, THE_DEFAULT_STACK_SIZE);
aToRebuildShaders = Standard_True;
}
else
{
if (aRequiredStackSize < myTraversalStackSize)
{
if (myTraversalStackSize > THE_DEFAULT_STACK_SIZE)
{
myTraversalStackSize = Max (aRequiredStackSize, THE_DEFAULT_STACK_SIZE);
aToRebuildShaders = Standard_True;
}
}
}
if (aToRebuildShaders)
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Info: Rebuild shaders with stack size: " << myTraversalStackSize << std::endl;
#endif
TCollection_AsciiString aStackSizeStr =
TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myTraversalStackSize);
myRaytraceShaderSource.SetPrefix (aStackSizeStr);
myPostFSAAShaderSource.SetPrefix (aStackSizeStr);
if (!myRaytraceShader->LoadSource (myGlContext, myRaytraceShaderSource.Source())
|| !myPostFSAAShader->LoadSource (myGlContext, myPostFSAAShaderSource.Source()))
{
return Standard_False;
}
if (!myRaytraceShader->Compile (myGlContext)
|| !myPostFSAAShader->Compile (myGlContext))
{
return Standard_False;
}
if (!myRaytraceProgram->Link (myGlContext)
|| !myPostFSAAProgram->Link (myGlContext))
{
return Standard_False;
}
}
}
if (myComputeInitStatus == OpenGl_RT_NONE)
{
if (!myGlContext->IsGlGreaterEqual (3, 1))
{
const TCollection_ExtendedString aMessage = "Ray-tracing requires OpenGL 3.1 and higher";
myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
return Standard_False;
}
TCollection_AsciiString aFolder = Graphic3d_ShaderProgram::ShadersFolder();
if (aFolder.IsEmpty())
{
const TCollection_ExtendedString aMessage = "Failed to locate shaders directory";
myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB, aMessage);
return Standard_False;
}
if (myIsRaytraceDataValid)
{
myTraversalStackSize = Max (THE_DEFAULT_STACK_SIZE,
myRaytraceGeometry.HighLevelTreeDepth() + myRaytraceGeometry.BottomLevelTreeDepth());
}
{
Handle(OpenGl_ShaderObject) aBasicVertShader = LoadShader (
ShaderSource (aFolder + "/RaytraceBase.vs"), GL_VERTEX_SHADER);
if (aBasicVertShader.IsNull())
{
return SafeFailBack ("Failed to set vertex shader source");
}
TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs", aFolder + "/RaytraceRender.fs" };
myRaytraceShaderSource.Load (aFiles, 2);
TCollection_AsciiString aStackSizeStr =
TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myTraversalStackSize);
myRaytraceShaderSource.SetPrefix (aStackSizeStr);
myRaytraceShader = LoadShader (myRaytraceShaderSource, GL_FRAGMENT_SHADER);
if (myRaytraceShader.IsNull())
{
aBasicVertShader->Release (myGlContext.operator->());
return SafeFailBack ("Failed to set ray-trace fragment shader source");
}
myRaytraceProgram = new OpenGl_ShaderProgram;
if (!myRaytraceProgram->Create (myGlContext))
{
aBasicVertShader->Release (myGlContext.operator->());
return SafeFailBack ("Failed to create ray-trace shader program");
}
if (!myRaytraceProgram->AttachShader (myGlContext, aBasicVertShader)
|| !myRaytraceProgram->AttachShader (myGlContext, myRaytraceShader))
{
aBasicVertShader->Release (myGlContext.operator->());
return SafeFailBack ("Failed to attach ray-trace shader objects");
}
if (!myRaytraceProgram->Link (myGlContext))
{
TCollection_AsciiString aLinkLog;
if (myRaytraceProgram->FetchInfoLog (myGlContext, aLinkLog))
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << aLinkLog << std::endl;
#endif
}
return SafeFailBack ("Failed to link ray-trace shader program");
}
}
{
Handle(OpenGl_ShaderObject) aBasicVertShader = LoadShader (
ShaderSource (aFolder + "/RaytraceBase.vs"), GL_VERTEX_SHADER);
if (aBasicVertShader.IsNull())
{
return SafeFailBack ("Failed to set vertex shader source");
}
TCollection_AsciiString aFiles[] = { aFolder + "/RaytraceBase.fs", aFolder + "/RaytraceSmooth.fs" };
myPostFSAAShaderSource.Load (aFiles, 2);
TCollection_AsciiString aStackSizeStr =
TCollection_AsciiString ("#define STACK_SIZE ") + TCollection_AsciiString (myTraversalStackSize);
myPostFSAAShaderSource.SetPrefix (aStackSizeStr);
myPostFSAAShader = LoadShader (myPostFSAAShaderSource, GL_FRAGMENT_SHADER);
if (myPostFSAAShader.IsNull())
{
aBasicVertShader->Release (myGlContext.operator->());
return SafeFailBack ("Failed to set FSAA fragment shader source");
}
myPostFSAAProgram = new OpenGl_ShaderProgram;
if (!myPostFSAAProgram->Create (myGlContext))
{
aBasicVertShader->Release (myGlContext.operator->());
return SafeFailBack ("Failed to create FSAA shader program");
}
if (!myPostFSAAProgram->AttachShader (myGlContext, aBasicVertShader)
|| !myPostFSAAProgram->AttachShader (myGlContext, myPostFSAAShader))
{
aBasicVertShader->Release (myGlContext.operator->());
return SafeFailBack ("Failed to attach FSAA shader objects");
}
if (!myPostFSAAProgram->Link (myGlContext))
{
TCollection_AsciiString aLinkLog;
if (myPostFSAAProgram->FetchInfoLog (myGlContext, aLinkLog))
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << aLinkLog << std::endl;
#endif
}
return SafeFailBack ("Failed to link FSAA shader program");
}
}
}
if (myComputeInitStatus == OpenGl_RT_NONE || aToRebuildShaders)
{
for (Standard_Integer anIndex = 0; anIndex < 2; ++anIndex)
{
Handle(OpenGl_ShaderProgram)& aShaderProgram =
(anIndex == 0) ? myRaytraceProgram : myPostFSAAProgram;
aShaderProgram->Bind (myGlContext);
aShaderProgram->SetSampler (myGlContext,
"uSceneMinPointTexture", OpenGl_RT_SceneMinPointTexture);
aShaderProgram->SetSampler (myGlContext,
"uSceneMaxPointTexture", OpenGl_RT_SceneMaxPointTexture);
aShaderProgram->SetSampler (myGlContext,
"uSceneNodeInfoTexture", OpenGl_RT_SceneNodeInfoTexture);
aShaderProgram->SetSampler (myGlContext,
"uObjectMinPointTexture", OpenGl_RT_ObjectMinPointTexture);
aShaderProgram->SetSampler (myGlContext,
"uObjectMaxPointTexture", OpenGl_RT_ObjectMaxPointTexture);
aShaderProgram->SetSampler (myGlContext,
"uObjectNodeInfoTexture", OpenGl_RT_ObjectNodeInfoTexture);
aShaderProgram->SetSampler (myGlContext,
"uGeometryVertexTexture", OpenGl_RT_GeometryVertexTexture);
aShaderProgram->SetSampler (myGlContext,
"uGeometryNormalTexture", OpenGl_RT_GeometryNormalTexture);
aShaderProgram->SetSampler (myGlContext,
"uGeometryTriangTexture", OpenGl_RT_GeometryTriangTexture);
aShaderProgram->SetSampler (myGlContext,
"uRaytraceMaterialTexture", OpenGl_RT_RaytraceMaterialTexture);
aShaderProgram->SetSampler (myGlContext,
"uRaytraceLightSrcTexture", OpenGl_RT_RaytraceLightSrcTexture);
if (anIndex == 1)
{
aShaderProgram->SetSampler (myGlContext,
"uFSAAInputTexture", OpenGl_RT_FSAAInputTexture);
}
myUniformLocations[anIndex][OpenGl_RT_aPosition] =
aShaderProgram->GetAttributeLocation (myGlContext, "aPosition");
myUniformLocations[anIndex][OpenGl_RT_uOriginLB] =
aShaderProgram->GetUniformLocation (myGlContext, "uOriginLB");
myUniformLocations[anIndex][OpenGl_RT_uOriginRB] =
aShaderProgram->GetUniformLocation (myGlContext, "uOriginRB");
myUniformLocations[anIndex][OpenGl_RT_uOriginLT] =
aShaderProgram->GetUniformLocation (myGlContext, "uOriginLT");
myUniformLocations[anIndex][OpenGl_RT_uOriginRT] =
aShaderProgram->GetUniformLocation (myGlContext, "uOriginRT");
myUniformLocations[anIndex][OpenGl_RT_uDirectLB] =
aShaderProgram->GetUniformLocation (myGlContext, "uDirectLB");
myUniformLocations[anIndex][OpenGl_RT_uDirectRB] =
aShaderProgram->GetUniformLocation (myGlContext, "uDirectRB");
myUniformLocations[anIndex][OpenGl_RT_uDirectLT] =
aShaderProgram->GetUniformLocation (myGlContext, "uDirectLT");
myUniformLocations[anIndex][OpenGl_RT_uDirectRT] =
aShaderProgram->GetUniformLocation (myGlContext, "uDirectRT");
myUniformLocations[anIndex][OpenGl_RT_uLightCount] =
aShaderProgram->GetUniformLocation (myGlContext, "uLightCount");
myUniformLocations[anIndex][OpenGl_RT_uLightAmbnt] =
aShaderProgram->GetUniformLocation (myGlContext, "uGlobalAmbient");
myUniformLocations[anIndex][OpenGl_RT_uSceneRad] =
aShaderProgram->GetUniformLocation (myGlContext, "uSceneRadius");
myUniformLocations[anIndex][OpenGl_RT_uSceneEps] =
aShaderProgram->GetUniformLocation (myGlContext, "uSceneEpsilon");
myUniformLocations[anIndex][OpenGl_RT_uShadEnabled] =
aShaderProgram->GetUniformLocation (myGlContext, "uShadowsEnable");
myUniformLocations[anIndex][OpenGl_RT_uReflEnabled] =
aShaderProgram->GetUniformLocation (myGlContext, "uReflectionsEnable");
myUniformLocations[anIndex][OpenGl_RT_uOffsetX] =
aShaderProgram->GetUniformLocation (myGlContext, "uOffsetX");
myUniformLocations[anIndex][OpenGl_RT_uOffsetY] =
aShaderProgram->GetUniformLocation (myGlContext, "uOffsetY");
myUniformLocations[anIndex][OpenGl_RT_uSamples] =
aShaderProgram->GetUniformLocation (myGlContext, "uSamples");
}
OpenGl_ShaderProgram::Unbind (myGlContext);
}
if (myComputeInitStatus != OpenGl_RT_NONE)
{
return myComputeInitStatus == OpenGl_RT_INIT;
}
if (myRaytraceFBO1.IsNull())
{
myRaytraceFBO1 = new OpenGl_FrameBuffer;
}
if (myRaytraceFBO2.IsNull())
{
myRaytraceFBO2 = new OpenGl_FrameBuffer;
}
const GLfloat aVertices[] = { -1.f, -1.f, 0.f,
-1.f, 1.f, 0.f,
1.f, 1.f, 0.f,
1.f, 1.f, 0.f,
1.f, -1.f, 0.f,
-1.f, -1.f, 0.f };
myRaytraceScreenQuad.Init (myGlContext, 3, 6, aVertices);
myComputeInitStatus = OpenGl_RT_INIT; // initialized in normal way
return Standard_True;
}
// =======================================================================
// function : NullifyResource
// purpose :
// =======================================================================
inline void NullifyResource (const Handle(OpenGl_Context)& theContext,
Handle(OpenGl_Resource)& theResource)
{
if (!theResource.IsNull())
{
theResource->Release (theContext.operator->());
theResource.Nullify();
}
}
// =======================================================================
// function : ReleaseRaytraceResources
// purpose : Releases OpenGL/GLSL shader programs
// =======================================================================
void OpenGl_Workspace::ReleaseRaytraceResources()
{
NullifyResource (myGlContext, myRaytraceFBO1);
NullifyResource (myGlContext, myRaytraceFBO2);
NullifyResource (myGlContext, myRaytraceShader);
NullifyResource (myGlContext, myPostFSAAShader);
NullifyResource (myGlContext, myRaytraceProgram);
NullifyResource (myGlContext, myPostFSAAProgram);
NullifyResource (myGlContext, mySceneNodeInfoTexture);
NullifyResource (myGlContext, mySceneMinPointTexture);
NullifyResource (myGlContext, mySceneMaxPointTexture);
NullifyResource (myGlContext, myObjectNodeInfoTexture);
NullifyResource (myGlContext, myObjectMinPointTexture);
NullifyResource (myGlContext, myObjectMaxPointTexture);
NullifyResource (myGlContext, myGeometryVertexTexture);
NullifyResource (myGlContext, myGeometryNormalTexture);
NullifyResource (myGlContext, myGeometryTriangTexture);
NullifyResource (myGlContext, myRaytraceLightSrcTexture);
NullifyResource (myGlContext, myRaytraceMaterialTexture);
if (myRaytraceScreenQuad.IsValid())
myRaytraceScreenQuad.Release (myGlContext.operator->());
}
// =======================================================================
// function : UploadRaytraceData
// purpose : Uploads ray-trace data to the GPU
// =======================================================================
Standard_Boolean OpenGl_Workspace::UploadRaytraceData()
{
if (!myGlContext->IsGlGreaterEqual (3, 1))
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: OpenGL version is less than 3.1" << std::endl;
#endif
return Standard_False;
}
/////////////////////////////////////////////////////////////////////////////
// Create OpenGL texture buffers
if (mySceneNodeInfoTexture.IsNull()) // create hight-level BVH buffers
{
mySceneNodeInfoTexture = new OpenGl_TextureBufferArb;
mySceneMinPointTexture = new OpenGl_TextureBufferArb;
mySceneMaxPointTexture = new OpenGl_TextureBufferArb;
if (!mySceneNodeInfoTexture->Create (myGlContext)
|| !mySceneMinPointTexture->Create (myGlContext)
|| !mySceneMaxPointTexture->Create (myGlContext))
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to create buffers for high-level scene BVH" << std::endl;
#endif
return Standard_False;
}
}
if (myObjectNodeInfoTexture.IsNull()) // create bottom-level BVH buffers
{
myObjectNodeInfoTexture = new OpenGl_TextureBufferArb;
myObjectMinPointTexture = new OpenGl_TextureBufferArb;
myObjectMaxPointTexture = new OpenGl_TextureBufferArb;
if (!myObjectNodeInfoTexture->Create (myGlContext)
|| !myObjectMinPointTexture->Create (myGlContext)
|| !myObjectMaxPointTexture->Create (myGlContext))
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to create buffers for bottom-level scene BVH" << std::endl;
#endif
return Standard_False;
}
}
if (myGeometryVertexTexture.IsNull()) // create geometry buffers
{
myGeometryVertexTexture = new OpenGl_TextureBufferArb;
myGeometryNormalTexture = new OpenGl_TextureBufferArb;
myGeometryTriangTexture = new OpenGl_TextureBufferArb;
if (!myGeometryVertexTexture->Create (myGlContext)
|| !myGeometryNormalTexture->Create (myGlContext)
|| !myGeometryTriangTexture->Create (myGlContext))
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to create buffers for triangulation data" << std::endl;
#endif
return Standard_False;
}
}
if (myRaytraceMaterialTexture.IsNull()) // create material buffer
{
myRaytraceMaterialTexture = new OpenGl_TextureBufferArb;
if (!myRaytraceMaterialTexture->Create (myGlContext))
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to create buffers for material data" << std::endl;
#endif
return Standard_False;
}
}
/////////////////////////////////////////////////////////////////////////////
// Write OpenGL texture buffers
const NCollection_Handle<BVH_Tree<Standard_ShortReal, 4> >& aBVH = myRaytraceGeometry.BVH();
bool aResult = true;
if (!aBVH->NodeInfoBuffer().empty())
{
aResult &= mySceneNodeInfoTexture->Init (myGlContext, 4,
aBVH->NodeInfoBuffer().size(), reinterpret_cast<const GLuint*> (&aBVH->NodeInfoBuffer().front()));
aResult &= mySceneMinPointTexture->Init (myGlContext, 4,
aBVH->MinPointBuffer().size(), reinterpret_cast<const GLfloat*> (&aBVH->MinPointBuffer().front()));
aResult &= mySceneMaxPointTexture->Init (myGlContext, 4,
aBVH->MaxPointBuffer().size(), reinterpret_cast<const GLfloat*> (&aBVH->MaxPointBuffer().front()));
}
if (!aResult)
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to upload buffers for high-level scene BVH" << std::endl;
#endif
return Standard_False;
}
Standard_Size aTotalVerticesNb = 0;
Standard_Size aTotalElementsNb = 0;
Standard_Size aTotalBVHNodesNb = 0;
for (Standard_Integer anElemIndex = 0; anElemIndex < myRaytraceGeometry.Size(); ++anElemIndex)
{
OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
myRaytraceGeometry.Objects().ChangeValue (anElemIndex).operator->());
Standard_ASSERT_RETURN (aTriangleSet != NULL,
"Error: Failed to get triangulation of OpenGL element", Standard_False);
aTotalVerticesNb += aTriangleSet->Vertices.size();
aTotalElementsNb += aTriangleSet->Elements.size();
Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
"Error: Failed to get bottom-level BVH of OpenGL element", Standard_False);
aTotalBVHNodesNb += aTriangleSet->BVH()->NodeInfoBuffer().size();
}
if (aTotalBVHNodesNb != 0)
{
aResult &= myObjectNodeInfoTexture->Init (
myGlContext, 4, aTotalBVHNodesNb, static_cast<const GLuint*> (NULL));
aResult &= myObjectMinPointTexture->Init (
myGlContext, 4, aTotalBVHNodesNb, static_cast<const GLfloat*> (NULL));
aResult &= myObjectMaxPointTexture->Init (
myGlContext, 4, aTotalBVHNodesNb, static_cast<const GLfloat*> (NULL));
}
if (!aResult)
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to upload buffers for bottom-level scene BVH" << std::endl;
#endif
return Standard_False;
}
if (aTotalElementsNb != 0)
{
aResult &= myGeometryTriangTexture->Init (
myGlContext, 4, aTotalElementsNb, static_cast<const GLuint*> (NULL));
}
if (aTotalVerticesNb != 0)
{
aResult &= myGeometryVertexTexture->Init (
myGlContext, 4, aTotalVerticesNb, static_cast<const GLfloat*> (NULL));
aResult &= myGeometryNormalTexture->Init (
myGlContext, 4, aTotalVerticesNb, static_cast<const GLfloat*> (NULL));
}
if (!aResult)
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to upload buffers for scene geometry" << std::endl;
#endif
return Standard_False;
}
for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
{
if (!aBVH->IsOuter (aNodeIdx))
continue;
OpenGl_TriangleSet* aTriangleSet = myRaytraceGeometry.TriangleSet (aNodeIdx);
Standard_ASSERT_RETURN (aTriangleSet != NULL,
"Error: Failed to get triangulation of OpenGL element", Standard_False);
const Standard_Integer aBVHOffset = myRaytraceGeometry.AccelerationOffset (aNodeIdx);
Standard_ASSERT_RETURN (aBVHOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET,
"Error: Failed to get offset for bottom-level BVH", Standard_False);
const size_t aBVHBuffserSize = aTriangleSet->BVH()->NodeInfoBuffer().size();
if (aBVHBuffserSize != 0)
{
aResult &= myObjectNodeInfoTexture->SubData (myGlContext, aBVHOffset,
aBVHBuffserSize, reinterpret_cast<const GLuint*> (&aTriangleSet->BVH()->NodeInfoBuffer().front()));
aResult &= myObjectMinPointTexture->SubData (myGlContext, aBVHOffset,
aBVHBuffserSize, reinterpret_cast<const GLfloat*> (&aTriangleSet->BVH()->MinPointBuffer().front()));
aResult &= myObjectMaxPointTexture->SubData (myGlContext, aBVHOffset,
aBVHBuffserSize, reinterpret_cast<const GLfloat*> (&aTriangleSet->BVH()->MaxPointBuffer().front()));
if (!aResult)
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to upload buffers for bottom-level scene BVHs" << std::endl;
#endif
return Standard_False;
}
}
const Standard_Integer aVerticesOffset = myRaytraceGeometry.VerticesOffset (aNodeIdx);
Standard_ASSERT_RETURN (aVerticesOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET,
"Error: Failed to get offset for triangulation vertices of OpenGL element", Standard_False);
if (!aTriangleSet->Vertices.empty())
{
aResult &= myGeometryNormalTexture->SubData (myGlContext, aVerticesOffset,
aTriangleSet->Normals.size(), reinterpret_cast<const GLfloat*> (&aTriangleSet->Normals.front()));
aResult &= myGeometryVertexTexture->SubData (myGlContext, aVerticesOffset,
aTriangleSet->Vertices.size(), reinterpret_cast<const GLfloat*> (&aTriangleSet->Vertices.front()));
}
const Standard_Integer anElementsOffset = myRaytraceGeometry.ElementsOffset (aNodeIdx);
Standard_ASSERT_RETURN (anElementsOffset != OpenGl_RaytraceGeometry::INVALID_OFFSET,
"Error: Failed to get offset for triangulation elements of OpenGL element", Standard_False);
if (!aTriangleSet->Elements.empty())
{
aResult &= myGeometryTriangTexture->SubData (myGlContext, anElementsOffset,
aTriangleSet->Elements.size(), reinterpret_cast<const GLuint*> (&aTriangleSet->Elements.front()));
}
if (!aResult)
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to upload triangulation buffers for OpenGL element" << std::endl;
#endif
return Standard_False;
}
}
if (myRaytraceGeometry.Materials.size() != 0)
{
const GLfloat* aDataPtr = myRaytraceGeometry.Materials.front().Packed();
aResult &= myRaytraceMaterialTexture->Init (
myGlContext, 4, myRaytraceGeometry.Materials.size() * 7, aDataPtr);
if (!aResult)
{
#ifdef RAY_TRACE_PRINT_INFO
std::cout << "Error: Failed to upload material buffer" << std::endl;
#endif
return Standard_False;
}
}
myIsRaytraceDataValid = myRaytraceGeometry.Objects().Size() != 0;
#ifdef RAY_TRACE_PRINT_INFO
Standard_ShortReal aMemUsed = 0.f;
for (Standard_Integer anElemIdx = 0; anElemIdx < myRaytraceGeometry.Size(); ++anElemIdx)
{
OpenGl_TriangleSet* aTriangleSet = dynamic_cast<OpenGl_TriangleSet*> (
myRaytraceGeometry.Objects().ChangeValue (anElemIdx).operator->());
aMemUsed += static_cast<Standard_ShortReal> (
aTriangleSet->Vertices.size() * sizeof (BVH_Vec4f));
aMemUsed += static_cast<Standard_ShortReal> (
aTriangleSet->Normals.size() * sizeof (BVH_Vec4f));
aMemUsed += static_cast<Standard_ShortReal> (
aTriangleSet->Elements.size() * sizeof (BVH_Vec4i));
aMemUsed += static_cast<Standard_ShortReal> (
aTriangleSet->BVH()->NodeInfoBuffer().size() * sizeof (BVH_Vec4i));
aMemUsed += static_cast<Standard_ShortReal> (
aTriangleSet->BVH()->MinPointBuffer().size() * sizeof (BVH_Vec4f));
aMemUsed += static_cast<Standard_ShortReal> (
aTriangleSet->BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec4f));
}
aMemUsed += static_cast<Standard_ShortReal> (
myRaytraceGeometry.BVH()->NodeInfoBuffer().size() * sizeof (BVH_Vec4i));
aMemUsed += static_cast<Standard_ShortReal> (
myRaytraceGeometry.BVH()->MinPointBuffer().size() * sizeof (BVH_Vec4f));
aMemUsed += static_cast<Standard_ShortReal> (
myRaytraceGeometry.BVH()->MaxPointBuffer().size() * sizeof (BVH_Vec4f));
std::cout << "GPU Memory Used (MB): ~" << aMemUsed / 1048576 << std::endl;
#endif
return aResult;
}
// =======================================================================
// function : ResizeRaytraceBuffers
// purpose : Resizes OpenGL frame buffers
// =======================================================================
Standard_Boolean OpenGl_Workspace::ResizeRaytraceBuffers (const Standard_Integer theSizeX,
const Standard_Integer theSizeY)
{
if (myRaytraceFBO1->GetVPSizeX() != theSizeX
|| myRaytraceFBO1->GetVPSizeY() != theSizeY)
{
myRaytraceFBO1->Init (myGlContext, theSizeX, theSizeY);
myRaytraceFBO2->Init (myGlContext, theSizeX, theSizeY);
}
return Standard_True;
}
// =======================================================================
// function : UpdateCamera
// purpose : Generates viewing rays for corners of screen quad
// =======================================================================
void OpenGl_Workspace::UpdateCamera (const NCollection_Mat4<GLdouble>& theOrientation,
const NCollection_Mat4<GLdouble>& theViewMapping,
OpenGl_Vec3 theOrigins[4],
OpenGl_Vec3 theDirects[4])
{
NCollection_Mat4<GLdouble> aInvModelProj;
// compute invserse model-view-projection matrix
(theViewMapping * theOrientation).Inverted (aInvModelProj);
Standard_Integer aOriginIndex = 0;
Standard_Integer aDirectIndex = 0;
for (Standard_Integer aY = -1; aY <= 1; aY += 2)
{
for (Standard_Integer aX = -1; aX <= 1; aX += 2)
{
OpenGl_Vec4d aOrigin (GLdouble(aX),
GLdouble(aY),
-1.0,
1.0);
aOrigin = aInvModelProj * aOrigin;
aOrigin.x() = aOrigin.x() / aOrigin.w();
aOrigin.y() = aOrigin.y() / aOrigin.w();
aOrigin.z() = aOrigin.z() / aOrigin.w();
OpenGl_Vec4d aDirect (GLdouble(aX),
GLdouble(aY),
1.0,
1.0);
aDirect = aInvModelProj * aDirect;
aDirect.x() = aDirect.x() / aDirect.w();
aDirect.y() = aDirect.y() / aDirect.w();
aDirect.z() = aDirect.z() / aDirect.w();
aDirect = aDirect - aOrigin;
GLdouble aInvLen = 1.0 / sqrt (aDirect.x() * aDirect.x() +
aDirect.y() * aDirect.y() +
aDirect.z() * aDirect.z());
theOrigins[aOriginIndex++] = OpenGl_Vec3 (static_cast<GLfloat> (aOrigin.x()),
static_cast<GLfloat> (aOrigin.y()),
static_cast<GLfloat> (aOrigin.z()));
theDirects[aDirectIndex++] = OpenGl_Vec3 (static_cast<GLfloat> (aDirect.x() * aInvLen),
static_cast<GLfloat> (aDirect.y() * aInvLen),
static_cast<GLfloat> (aDirect.z() * aInvLen));
}
}
}
// =======================================================================
// function : RunRaytraceShaders
// purpose : Runs ray-tracing shader programs
// =======================================================================
Standard_Boolean OpenGl_Workspace::RunRaytraceShaders (const Graphic3d_CView& theCView,
const Standard_Integer theSizeX,
const Standard_Integer theSizeY,
const OpenGl_Vec3 theOrigins[4],
const OpenGl_Vec3 theDirects[4],
OpenGl_FrameBuffer* theFrameBuffer)
{
mySceneMinPointTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMinPointTexture);
mySceneMaxPointTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneMaxPointTexture);
mySceneNodeInfoTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_SceneNodeInfoTexture);
myObjectMinPointTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_ObjectMinPointTexture);
myObjectMaxPointTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_ObjectMaxPointTexture);
myObjectNodeInfoTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_ObjectNodeInfoTexture);
myGeometryVertexTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryVertexTexture);
myGeometryNormalTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryNormalTexture);
myGeometryTriangTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_GeometryTriangTexture);
myRaytraceMaterialTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceMaterialTexture);
myRaytraceLightSrcTexture->BindTexture (myGlContext, GL_TEXTURE0 + OpenGl_RT_RaytraceLightSrcTexture);
if (theCView.IsAntialiasingEnabled) // render source image to FBO
{
myRaytraceFBO1->BindBuffer (myGlContext);
glDisable (GL_BLEND);
}
myRaytraceProgram->Bind (myGlContext);
Standard_Integer aLightSourceBufferSize =
static_cast<Standard_Integer> (myRaytraceGeometry.Sources.size());
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uOriginLB], theOrigins[0]);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uOriginRB], theOrigins[1]);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uOriginLT], theOrigins[2]);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uOriginRT], theOrigins[3]);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uDirectLB], theDirects[0]);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uDirectRB], theDirects[1]);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uDirectLT], theDirects[2]);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uDirectRT], theDirects[3]);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uSceneRad], myRaytraceSceneRadius);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uSceneEps], myRaytraceSceneEpsilon);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uLightCount], aLightSourceBufferSize);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uLightAmbnt], myRaytraceGeometry.Ambient);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uShadEnabled], theCView.IsShadowsEnabled);
myRaytraceProgram->SetUniform (myGlContext,
myUniformLocations[0][OpenGl_RT_uReflEnabled], theCView.IsReflectionsEnabled);
myGlContext->core20fwd->glEnableVertexAttribArray (
myUniformLocations[0][OpenGl_RT_aPosition]);
{
myGlContext->core20fwd->glVertexAttribPointer (
myUniformLocations[0][OpenGl_RT_aPosition], 3, GL_FLOAT, GL_FALSE, 0, NULL);
myGlContext->core15fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
}
myGlContext->core20fwd->glDisableVertexAttribArray (
myUniformLocations[0][OpenGl_RT_aPosition]);
if (!theCView.IsAntialiasingEnabled)
{
myRaytraceProgram->Unbind (myGlContext);
return Standard_True;
}
myGlContext->core20fwd->glActiveTexture (
GL_TEXTURE0 + OpenGl_RT_FSAAInputTexture); // texture unit for FBO texture
myRaytraceFBO1->BindTexture (myGlContext);
myPostFSAAProgram->Bind (myGlContext);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uOriginLB], theOrigins[0]);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uOriginRB], theOrigins[1]);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uOriginLT], theOrigins[2]);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uOriginRT], theOrigins[3]);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uDirectLB], theDirects[0]);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uDirectRB], theDirects[1]);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uDirectLT], theDirects[2]);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uDirectRT], theDirects[3]);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uSceneRad], myRaytraceSceneRadius);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uSceneEps], myRaytraceSceneEpsilon);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uLightCount], aLightSourceBufferSize);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uLightAmbnt], myRaytraceGeometry.Ambient);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uShadEnabled], theCView.IsShadowsEnabled);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uReflEnabled], theCView.IsReflectionsEnabled);
const Standard_ShortReal aMaxOffset = 0.559017f;
const Standard_ShortReal aMinOffset = 0.186339f;
myGlContext->core20fwd->glEnableVertexAttribArray (
myUniformLocations[1][OpenGl_RT_aPosition]);
myGlContext->core20fwd->glVertexAttribPointer (
myUniformLocations[1][OpenGl_RT_aPosition], 3, GL_FLOAT, GL_FALSE, 0, NULL);
// Perform multi-pass adaptive FSAA using ping-pong technique
for (Standard_Integer anIt = 0; anIt < 4; ++anIt)
{
GLfloat aOffsetX = 1.f / theSizeX;
GLfloat aOffsetY = 1.f / theSizeY;
if (anIt < 2)
{
aOffsetX *= anIt < 1 ? aMinOffset : -aMaxOffset;
aOffsetY *= anIt < 1 ? aMaxOffset : aMinOffset;
}
else
{
aOffsetX *= anIt > 2 ? aMaxOffset : -aMinOffset;
aOffsetY *= anIt > 2 ? -aMinOffset : -aMaxOffset;
}
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uSamples], anIt + 2);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uOffsetX], aOffsetX);
myPostFSAAProgram->SetUniform (myGlContext,
myUniformLocations[1][OpenGl_RT_uOffsetY], aOffsetY);
Handle(OpenGl_FrameBuffer)& aFramebuffer = anIt % 2 ? myRaytraceFBO1 : myRaytraceFBO2;
if (anIt == 3) // disable FBO on last iteration
{
glEnable (GL_BLEND);
if (theFrameBuffer != NULL)
theFrameBuffer->BindBuffer (myGlContext);
}
else
{
aFramebuffer->BindBuffer (myGlContext);
}
myGlContext->core15fwd->glDrawArrays (GL_TRIANGLES, 0, 6);
if (anIt != 3) // set input for the next pass
{
aFramebuffer->BindTexture (myGlContext);
aFramebuffer->UnbindBuffer (myGlContext);
}
}
myGlContext->core20fwd->glDisableVertexAttribArray (
myUniformLocations[1][OpenGl_RT_aPosition]);
myPostFSAAProgram->Unbind (myGlContext);
return Standard_True;
}
// =======================================================================
// function : Raytrace
// purpose : Redraws the window using OpenGL/GLSL ray-tracing
// =======================================================================
Standard_Boolean OpenGl_Workspace::Raytrace (const Graphic3d_CView& theCView,
const Standard_Integer theSizeX,
const Standard_Integer theSizeY,
const Standard_Boolean theToSwap,
OpenGl_FrameBuffer* theFrameBuffer)
{
if (!UpdateRaytraceGeometry (Standard_True))
return Standard_False;
if (!InitRaytraceResources())
return Standard_False;
if (!ResizeRaytraceBuffers (theSizeX, theSizeY))
return Standard_False;
if (!UpdateRaytraceEnvironmentMap())
return Standard_False;
// Get model-view and projection matrices
TColStd_Array2OfReal theOrientation (0, 3, 0, 3);
TColStd_Array2OfReal theViewMapping (0, 3, 0, 3);
myView->GetMatrices (theOrientation, theViewMapping);
NCollection_Mat4<GLdouble> aOrientationMatrix;
NCollection_Mat4<GLdouble> aViewMappingMatrix;
for (Standard_Integer j = 0; j < 4; ++j)
{
for (Standard_Integer i = 0; i < 4; ++i)
{
aOrientationMatrix [4 * j + i] = theOrientation (i, j);
aViewMappingMatrix [4 * j + i] = theViewMapping (i, j);
}
}
NCollection_Mat4<GLdouble> aInvOrientationMatrix;
aOrientationMatrix.Inverted (aInvOrientationMatrix);
if (!UpdateRaytraceLightSources (aInvOrientationMatrix))
return Standard_False;
OpenGl_Vec3 aOrigins[4];
OpenGl_Vec3 aDirects[4];
UpdateCamera (aOrientationMatrix,
aViewMappingMatrix,
aOrigins,
aDirects);
// Draw background
glPushAttrib (GL_ENABLE_BIT |
GL_CURRENT_BIT |
GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT);
glDisable (GL_DEPTH_TEST);
if (NamedStatus & OPENGL_NS_WHITEBACK)
{
glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
}
else
{
glClearColor (myBgColor.rgb[0],
myBgColor.rgb[1],
myBgColor.rgb[2],
1.0f);
}
glClear (GL_COLOR_BUFFER_BIT);
if (theFrameBuffer != NULL)
theFrameBuffer->BindBuffer (myGlContext);
myView->DrawBackground (*this);
// Generate ray-traced image
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_SRC_ALPHA);
if (myIsRaytraceDataValid)
{
myRaytraceScreenQuad.Bind (myGlContext);
RunRaytraceShaders (theCView,
theSizeX,
theSizeY,
aOrigins,
aDirects,
theFrameBuffer);
myRaytraceScreenQuad.Unbind (myGlContext);
}
if (theFrameBuffer != NULL)
theFrameBuffer->UnbindBuffer (myGlContext);
glPopAttrib();
// Swap the buffers
if (theToSwap)
{
GetGlContext()->SwapBuffers();
myBackBufferRestored = Standard_False;
}
else
{
glFlush();
}
return Standard_True;
}