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

0026536: Visualization - Ray-tracing engine: improving BVH traverse and fixing texture support

Replace 64-bit handles of bindless textures by uvec2 type in GLSL code for compatibility with AMD drivers.
OpenGl_View::initProgram() - fix NULL-dereference.
This commit is contained in:
dbp 2015-08-27 12:46:22 +03:00 committed by bugmaster
parent 1bd2fee414
commit 47e9c17868
9 changed files with 242 additions and 351 deletions

View File

@ -144,7 +144,7 @@ public:
//! Is node a leaf (outer)?
Standard_Boolean IsOuter (const Standard_Integer theNodeIndex) const
{
return BVH::Array<Standard_Integer, 4>::Value (myNodeInfoBuffer, theNodeIndex).x() > 0;
return BVH::Array<Standard_Integer, 4>::Value (myNodeInfoBuffer, theNodeIndex).x() != 0;
}
//! Sets node type to 'outer'.

View File

@ -236,7 +236,7 @@ struct OpenGL_BVHParallelBuilder
Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
{
#ifdef RAY_TRACE_PRINT_INFO
OSD_Timer aTimer;
OSD_Timer aTimer;
#endif
MarkDirty(); // force BVH rebuilding
@ -261,6 +261,18 @@ Standard_Boolean OpenGl_RaytraceGeometry::ProcessAcceleration()
Standard_ASSERT_RETURN (!aTriangleSet->BVH().IsNull(),
"Error! Failed to update bottom-level BVH of OpenGL element", Standard_False);
NCollection_Handle<BVH_Tree<Standard_ShortReal, 3> > aBVH = aTriangleSet->BVH();
// correct data array of bottom-level BVH to set special flag for outer
// nodes in order to distinguish them from outer nodes of top-level BVH
for (Standard_Integer aNodeIdx = 0; aNodeIdx < aBVH->Length(); ++aNodeIdx)
{
if (aBVH->IsOuter (aNodeIdx))
{
aBVH->NodeInfoBuffer()[aNodeIdx].x() = -1;
}
}
myBottomLevelTreeDepth = Max (myBottomLevelTreeDepth, aTriangleSet->BVH()->Depth());
}
@ -475,13 +487,23 @@ Standard_Boolean OpenGl_RaytraceGeometry::UpdateTextureHandles (const Handle(Ope
return Standard_False;
}
if (myTextureSampler.IsNull())
{
myTextureSampler = new OpenGl_Sampler();
myTextureSampler->Init (*theContext.operator->());
myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_WRAP_S, GL_REPEAT);
myTextureSampler->SetParameter (*theContext.operator->(), GL_TEXTURE_WRAP_T, GL_REPEAT);
}
myTextureHandles.clear();
#if !defined(GL_ES_VERSION_2_0)
for (Standard_Integer anIdx = 0; anIdx < myTextures.Size(); ++anIdx)
{
const GLuint64 aHandle = theContext->arbTexBindless->glGetTextureHandleARB (
myTextures.Value (anIdx)->TextureId());
const GLuint64 aHandle = theContext->arbTexBindless->glGetTextureSamplerHandleARB (
myTextures.Value (anIdx)->TextureId(), myTextureSampler->SamplerID());
if (glGetError() != GL_NO_ERROR)
{

View File

@ -22,6 +22,7 @@
#include <NCollection_StdAllocator.hxx>
#include <OpenGl_TextureBufferArb.hxx>
#include <OpenGl_Texture.hxx>
#include <OpenGl_Sampler.hxx>
class OpenGl_Element;
struct OpenGl_ElementNode;
@ -331,6 +332,16 @@ public: //! @name methods related to texture management
return !myTextures.IsEmpty();
}
//! Releases OpenGL resources.
void ReleaseResources (const Handle(OpenGl_Context)& theContext)
{
if (!myTextureSampler.IsNull())
{
myTextureSampler->Release (theContext.operator->());
myTextureSampler.Nullify();
}
}
public: //! @name auxiliary methods
//! Returns depth of high-level scene BVH from last build.
@ -348,6 +359,7 @@ public: //! @name auxiliary methods
protected:
NCollection_Vector<Handle(OpenGl_Texture)> myTextures; //!< Array of texture maps shared between rendered objects
Handle(OpenGl_Sampler) myTextureSampler; //!< Sampler object providing fixed sampling params for texures
std::vector<GLuint64> myTextureHandles; //!< Array of unique 64-bit texture handles obtained from OpenGL
Standard_Integer myHighLevelTreeDepth; //!< Depth of high-level scene BVH from last build
Standard_Integer myBottomLevelTreeDepth; //!< Maximum depth of bottom-level scene BVHs from last build

View File

@ -26,6 +26,7 @@
#include <OpenGl_ShaderManager.hxx>
#include <OpenGl_ArbTexBindless.hxx>
#include <OpenGl_GlCore32.hxx>
OpenGl_VariableSetterSelector OpenGl_ShaderProgram::mySetterSelector = OpenGl_VariableSetterSelector();
@ -791,30 +792,30 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
// =======================================================================
// function : SetUniform
// purpose : Specifies the value of the 64-bit unsigned uniform variable
// purpose :
// =======================================================================
Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
const GLchar* theName,
GLuint64 theValue)
const OpenGl_Vec2u& theValue)
{
return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
}
// =======================================================================
// function : SetUniform
// purpose : Specifies the value of the 64-bit unsigned uniform variable
// purpose :
// =======================================================================
Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
GLint theLocation,
GLuint64 theValue)
const OpenGl_Vec2u& theValue)
{
if (theCtx->arbTexBindless == NULL || myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
if (theCtx->core32 == NULL || myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
{
return Standard_False;
}
#if !defined(GL_ES_VERSION_2_0)
theCtx->arbTexBindless->glUniformHandleui64ARB (theLocation, theValue);
theCtx->core32->glUniform2uiv (theLocation, 1, theValue.GetData());
#endif
return Standard_True;
@ -822,32 +823,32 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
// =======================================================================
// function : SetUniform
// purpose : Specifies the value of the 64-bit unsigned uniform array
// purpose :
// =======================================================================
Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
const GLchar* theName,
const GLsizei theCount,
const GLuint64* theValue)
const OpenGl_Vec2u* theValue)
{
return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theCount, theValue);
}
// =======================================================================
// function : SetUniform
// purpose : Specifies the value of the 64-bit unsigned uniform array
// purpose :
// =======================================================================
Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
GLint theLocation,
const GLsizei theCount,
const GLuint64* theValue)
const OpenGl_Vec2u* theValue)
{
if (theCtx->arbTexBindless == NULL || myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
if (theCtx->core32 == NULL || myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
{
return Standard_False;
}
#if !defined(GL_ES_VERSION_2_0)
theCtx->arbTexBindless->glUniformHandleui64vARB (theLocation, theCount, theValue);
theCtx->core32->glUniform2uiv (theLocation, theCount, theValue->GetData());
#endif
return Standard_True;

View File

@ -365,27 +365,27 @@ public:
public:
//! Specifies the value of the 64-bit unsigned integer uniform variable.
//! Specifies the value of the unsigned integer uniform 2D vector (uvec2).
Standard_EXPORT Standard_Boolean SetUniform (const Handle(OpenGl_Context)& theCtx,
const GLchar* theName,
GLuint64 theValue);
const OpenGl_Vec2u& theValue);
//! Specifies the value of the 64-bit unsigned integer uniform variable.
//! Specifies the value of the unsigned integer uniform 2D vector (uvec2).
Standard_EXPORT Standard_Boolean SetUniform (const Handle(OpenGl_Context)& theCtx,
GLint theLocation,
GLuint64 theValue);
const OpenGl_Vec2u& theValue);
//! Specifies the value of the 64-bit unsigned integer uniform array.
//! Specifies the value of the uvec2 uniform array
Standard_EXPORT Standard_Boolean SetUniform (const Handle(OpenGl_Context)& theCtx,
const GLchar* theName,
const GLsizei theCount,
const GLuint64* theValue);
const OpenGl_Vec2u* theValue);
//! Specifies the value of the 64-bit unsigned integer uniform array.
//! Specifies the value of the uvec2 uniform array
Standard_EXPORT Standard_Boolean SetUniform (const Handle(OpenGl_Context)& theCtx,
GLint theLocation,
const GLsizei theCount,
const GLuint64* theValue);
const OpenGl_Vec2u* theValue);
public:

View File

@ -1089,7 +1089,10 @@ void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintCont
case Visual3d_TOD_ENVIRONMENT:
theWorkspace->NamedStatus |= OPENGL_NS_FORBIDSETTEX;
theWorkspace->EnableTexture (myTextureEnv);
if (theCView.RenderParams.Method != Graphic3d_RM_RAYTRACING)
{
theWorkspace->EnableTexture (myTextureEnv);
}
// Render the view
RenderStructs (theWorkspace, theReadDrawFbo, theCView, theToDrawImmediate);
theWorkspace->DisableTexture();
@ -1106,7 +1109,10 @@ void OpenGl_View::RedrawScene (const Handle(OpenGl_PrinterContext)& thePrintCont
if (theWorkspace->NamedStatus & OPENGL_NS_2NDPASSNEED)
{
theWorkspace->NamedStatus |= OPENGL_NS_2NDPASSDO;
theWorkspace->EnableTexture (myTextureEnv);
if (theCView.RenderParams.Method != Graphic3d_RM_RAYTRACING)
{
theWorkspace->EnableTexture (myTextureEnv);
}
// Remember OpenGl properties
GLint aSaveBlendDst = GL_ONE_MINUS_SRC_ALPHA, aSaveBlendSrc = GL_SRC_ALPHA;

View File

@ -1216,8 +1216,7 @@ Handle(OpenGl_ShaderProgram) OpenGl_View::initProgram (const Handle(OpenGl_Conte
}
else if (theGlContext->caps->glslWarnings)
{
myRaytraceProgram->FetchInfoLog (theGlContext, aLinkLog);
aProgram->FetchInfoLog (theGlContext, aLinkLog);
if (!aLinkLog.IsEmpty() && !aLinkLog.IsEqual ("No errors.\n"))
{
const TCollection_ExtendedString aMessage = TCollection_ExtendedString (
@ -1658,6 +1657,8 @@ void OpenGl_View::releaseRaytraceResources (const Handle(OpenGl_Context)& theGlC
nullifyResource (theGlContext, myRaytraceLightSrcTexture);
nullifyResource (theGlContext, myRaytraceMaterialTexture);
myRaytraceGeometry.ReleaseResources (theGlContext);
if (myRaytraceScreenQuad.IsValid())
myRaytraceScreenQuad.Release (theGlContext.operator->());
}
@ -2257,8 +2258,10 @@ Standard_Boolean OpenGl_View::setUniformState (const Graphic3d_CView& the
// Set array of 64-bit texture handles
if (theGlContext->arbTexBindless != NULL && myRaytraceGeometry.HasTextures())
{
const std::vector<GLuint64>& aTextures = myRaytraceGeometry.TextureHandles();
theProgram->SetUniform (theGlContext, myUniformLocations[theProgramId][OpenGl_RT_uTexSamplersArray],
static_cast<GLsizei> (myRaytraceGeometry.TextureHandles().size()), &myRaytraceGeometry.TextureHandles()[0]);
static_cast<GLsizei> (aTextures.size()), (OpenGl_Vec2u* )&aTextures.front());
}
// Set background colors (only gradient background supported)

View File

@ -687,7 +687,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse)
dot (aTrsfRow2, aTexCoord));
vec3 aTexColor = textureLod (
uTextureSamplers[int (aMaterial.Kd.w)], aTexCoord.st, 0.f).rgb;
sampler2D (uTextureSamplers[int (aMaterial.Kd.w)]), aTexCoord.st, 0.f).rgb;
aMaterial.Kd.rgb *= aTexColor;
}

View File

@ -89,7 +89,7 @@ uniform float uSceneEpsilon;
#ifdef USE_TEXTURES
//! Unique 64-bit handles of OpenGL textures.
uniform sampler2D uTextureSamplers[MAX_TEX_NUMBER];
uniform uvec2 uTextureSamplers[MAX_TEX_NUMBER];
#endif
//! Top color of gradient background.
@ -201,9 +201,9 @@ vec3 MatrixColMultiplyPnt (in vec3 v,
in vec4 m2,
in vec4 m3)
{
return vec3 (m0[0] * v.x + m1[0] * v.y + m2[0] * v.z + m3[0],
m0[1] * v.x + m1[1] * v.y + m2[1] * v.z + m3[1],
m0[2] * v.x + m1[2] * v.y + m2[2] * v.z + m3[2]);
return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z + m3.x,
m0.y * v.x + m1.y * v.y + m2.y * v.z + m3.y,
m0.z * v.x + m1.z * v.y + m2.z * v.z + m3.z);
}
// =======================================================================
@ -213,12 +213,11 @@ vec3 MatrixColMultiplyPnt (in vec3 v,
vec3 MatrixColMultiplyDir (in vec3 v,
in vec4 m0,
in vec4 m1,
in vec4 m2,
in vec4 m3)
in vec4 m2)
{
return vec3 (m0[0] * v.x + m1[0] * v.y + m2[0] * v.z,
m0[1] * v.x + m1[1] * v.y + m2[1] * v.z,
m0[2] * v.x + m1[2] * v.y + m2[2] * v.z);
return vec3 (m0.x * v.x + m1.x * v.y + m2.x * v.z,
m0.y * v.x + m1.y * v.y + m2.y * v.z,
m0.z * v.x + m1.z * v.y + m2.z * v.z);
}
//=======================================================================
@ -353,21 +352,53 @@ float IntersectTriangle (in SRay theRay,
//! Global stack shared between traversal functions.
int Stack[STACK_SIZE];
// =======================================================================
// function : ObjectNearestHit
// purpose : Finds intersection with nearest object triangle
// =======================================================================
ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
in SRay theRay, in vec3 theInverse, inout SIntersect theHit, in int theSentinel)
{
int aHead = theSentinel; // stack pointer
int aNode = theBVHOffset; // node to visit
#define MATERIAL_AMBN(index) (18 * index + 0)
#define MATERIAL_DIFF(index) (18 * index + 1)
#define MATERIAL_SPEC(index) (18 * index + 2)
#define MATERIAL_EMIS(index) (18 * index + 3)
#define MATERIAL_REFL(index) (18 * index + 4)
#define MATERIAL_REFR(index) (18 * index + 5)
#define MATERIAL_TRAN(index) (18 * index + 6)
#define MATERIAL_TRS1(index) (18 * index + 7)
#define MATERIAL_TRS2(index) (18 * index + 8)
#define MATERIAL_TRS3(index) (18 * index + 9)
struct SSubTree
{
//! Transformed ray.
SRay TrsfRay;
//! Inversed ray direction.
vec3 Inverse;
//! Parameters of sub-root node.
ivec4 SubData;
};
#define TRS_OFFSET(treelet) treelet.SubData.x
#define BVH_OFFSET(treelet) treelet.SubData.y
#define VRT_OFFSET(treelet) treelet.SubData.z
#define TRG_OFFSET(treelet) treelet.SubData.w
#define EMPTY_ROOT ivec4(0)
// =======================================================================
// function : SceneNearestHit
// purpose : Finds intersection with nearest scene triangle
// =======================================================================
ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
{
ivec4 aTriIndex = INALID_HIT;
int aNode = 0; // node to traverse
int aHead = -1; // pointer of stack
int aStop = -1; // BVH level switch
SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
for (bool toContinue = true; toContinue;)
{
ivec3 aData = texelFetch (uSceneNodeInfoTexture, aNode).xyz;
ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
if (aData.x == 0) // if inner node
{
@ -375,22 +406,22 @@ ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgO
float aTimeLft;
float aTimeRgh;
aData.y += theBVHOffset;
aData.z += theBVHOffset;
aData.y += BVH_OFFSET (aSubTree);
aData.z += BVH_OFFSET (aSubTree);
vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
vec3 aTime0 = (aNodeMinLft - aSubTree.TrsfRay.Origin) * aSubTree.Inverse;
vec3 aTime1 = (aNodeMaxLft - aSubTree.TrsfRay.Origin) * aSubTree.Inverse;
vec3 aTimeMax = max (aTime0, aTime1);
vec3 aTimeMin = min (aTime0, aTime1);
aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
aTime0 = (aNodeMinRgh - aSubTree.TrsfRay.Origin) * aSubTree.Inverse;
aTime1 = (aNodeMaxRgh - aSubTree.TrsfRay.Origin) * aSubTree.Inverse;
aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
@ -405,88 +436,107 @@ ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgO
int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theHit.Time);
if (bool(aHitLft & aHitRgh))
aNode = (aHitLft != 0) ? aData.y : aData.z;
if (aHitLft + aHitRgh == 2) // hit both children
{
aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
}
else
else if (aHitLft == aHitRgh) // no hit
{
if (bool(aHitLft | aHitRgh))
{
aNode = bool(aHitLft) ? aData.y : aData.z;
}
else
{
toContinue = (aHead != theSentinel);
toContinue = (aHead >= 0);
if (toContinue)
aNode = Stack[aHead--];
if (aHead == aStop) // go to top-level BVH
{
aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
}
aNode = Stack[abs (aHead)]; --aHead;
}
}
else // if leaf node
else if (aData.x < 0) // leaf node (containg triangles)
{
vec3 aNormal;
vec2 aParams;
for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
{
ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += theVrtOffset).xyz;
vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += theVrtOffset).xyz;
vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += theVrtOffset).xyz;
vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz;
vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz;
vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz;
float aTime = IntersectTriangle (theRay,
aPoint0,
aPoint1,
aPoint2,
aParams,
aNormal);
float aTime = IntersectTriangle (aSubTree.TrsfRay,
aPoint0, aPoint1, aPoint2, aParams, aNormal);
if (aTime < theHit.Time)
{
aTriIndex = aTriangle;
theTrsfId = TRS_OFFSET (aSubTree);
theHit = SIntersect (aTime, aParams, aNormal);
}
}
toContinue = (aHead != theSentinel);
toContinue = (aHead >= 0);
if (toContinue)
aNode = Stack[aHead--];
if (aHead == aStop) // go to top-level BVH
{
aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
}
aNode = Stack[abs (aHead)]; --aHead;
}
else if (aData.x > 0) // switch node
{
aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1);
vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
aInvTransf0,
aInvTransf1,
aInvTransf2);
aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) /
max (abs (aSubTree.TrsfRay.Direct), SMALL);
aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin,
aInvTransf0,
aInvTransf1,
aInvTransf2,
aInvTransf3);
aNode = BVH_OFFSET (aSubTree); // go to sub-root node
aStop = aHead; // store current stack pointer
}
}
return aTriIndex;
}
#define MATERIAL_AMBN(index) (18 * index + 0)
#define MATERIAL_DIFF(index) (18 * index + 1)
#define MATERIAL_SPEC(index) (18 * index + 2)
#define MATERIAL_EMIS(index) (18 * index + 3)
#define MATERIAL_REFL(index) (18 * index + 4)
#define MATERIAL_REFR(index) (18 * index + 5)
#define MATERIAL_TRAN(index) (18 * index + 6)
#define MATERIAL_TRS1(index) (18 * index + 7)
#define MATERIAL_TRS2(index) (18 * index + 8)
#define MATERIAL_TRS3(index) (18 * index + 9)
// =======================================================================
// function : ObjectAnyHit
// purpose : Finds intersection with any object triangle
// function : SceneAnyHit
// purpose : Finds intersection with any scene triangle
// =======================================================================
float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
in SRay theRay, in vec3 theInverse, in float theDistance, in int theSentinel)
float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
{
int aHead = theSentinel; // stack pointer
int aNode = theBVHOffset; // node to visit
float aFactor = 1.f;
int aNode = 0; // node to traverse
int aHead = -1; // pointer of stack
int aStop = -1; // BVH level switch
SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
for (bool toContinue = true; toContinue;)
{
ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
@ -497,22 +547,22 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
float aTimeLft;
float aTimeRgh;
aData.y += theBVHOffset;
aData.z += theBVHOffset;
aData.y += BVH_OFFSET (aSubTree);
aData.z += BVH_OFFSET (aSubTree);
vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
vec3 aTime0 = (aNodeMinLft - aSubTree.TrsfRay.Origin) * aSubTree.Inverse;
vec3 aTime1 = (aNodeMaxLft - aSubTree.TrsfRay.Origin) * aSubTree.Inverse;
vec3 aTimeMax = max (aTime0, aTime1);
vec3 aTimeMin = min (aTime0, aTime1);
aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
aTime0 = (aNodeMinRgh - aSubTree.TrsfRay.Origin) * aSubTree.Inverse;
aTime1 = (aNodeMaxRgh - aSubTree.TrsfRay.Origin) * aSubTree.Inverse;
aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
@ -527,46 +577,41 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
if (bool(aHitLft & aHitRgh))
aNode = (aHitLft != 0) ? aData.y : aData.z;
if (aHitLft + aHitRgh == 2) // hit both children
{
aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
}
else
else if (aHitLft == aHitRgh) // no hit
{
if (bool(aHitLft | aHitRgh))
{
aNode = bool(aHitLft) ? aData.y : aData.z;
}
else
{
toContinue = (aHead != theSentinel);
toContinue = (aHead >= 0);
if (toContinue)
aNode = Stack[aHead--];
if (aHead == aStop) // go to top-level BVH
{
aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
}
aNode = Stack[abs (aHead)]; --aHead;
}
}
else // if leaf node
else if (aData.x < 0) // leaf node
{
vec3 aNormal;
vec2 aParams;
for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
{
ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x + theVrtOffset).xyz;
vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y + theVrtOffset).xyz;
vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z + theVrtOffset).xyz;
vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz;
vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz;
vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz;
float aTime = IntersectTriangle (theRay,
aPoint0,
aPoint1,
aPoint2,
aParams,
aNormal);
float aTime = IntersectTriangle (aSubTree.TrsfRay,
aPoint0, aPoint1, aPoint2, aParams, aNormal);
#ifdef TRANSPARENT_SHADOWS
if (aTime < theDistance)
@ -581,238 +626,40 @@ float ObjectAnyHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffse
#endif
}
toContinue = (aHead != theSentinel) && (aFactor > 0.1f);
toContinue = (aHead >= 0) && (aFactor > 0.1f);
if (toContinue)
aNode = Stack[aHead--];
if (aHead == aStop) // go to top-level BVH
{
aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
}
aNode = Stack[abs (aHead)]; --aHead;
}
}
return aFactor;
}
// =======================================================================
// function : SceneNearestHit
// purpose : Finds intersection with nearest scene triangle
// =======================================================================
ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
{
int aHead = -1; // stack pointer
int aNode = 0; // node to visit
ivec4 aHitObject = INALID_HIT;
for (bool toContinue = true; toContinue;)
{
ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
if (aData.x != 0) // if leaf node
else if (aData.x > 0) // switch node
{
vec3 aNodeMin = texelFetch (uSceneMinPointTexture, aNode).xyz;
vec3 aNodeMax = texelFetch (uSceneMaxPointTexture, aNode).xyz;
aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
vec3 aTime0 = (aNodeMin - theRay.Origin) * theInverse;
vec3 aTime1 = (aNodeMax - theRay.Origin) * theInverse;
vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 0);
vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 1);
vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 2);
vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, TRS_OFFSET (aSubTree) + 3);
vec3 aTimes = min (aTime0, aTime1);
aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
aInvTransf0,
aInvTransf1,
aInvTransf2);
if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
{
// fetch object transformation
int aTrsfId = (aData.x - 1) * 4;
aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin,
aInvTransf0,
aInvTransf1,
aInvTransf2,
aInvTransf3);
vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0);
vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1);
vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2);
vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, aTrsfId + 3);
aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) / max (abs (aSubTree.TrsfRay.Direct), SMALL);
SRay aTrsfRay = SRay (
MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
aNode = BVH_OFFSET (aSubTree); // go to sub-root node
vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
aTrsfInverse = mix (-aTrsfInverse, aTrsfInverse, step (ZERO, aTrsfRay.Direct));
ivec4 aTriIndex = ObjectNearestHit (
aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theHit, aHead);
if (aTriIndex.x != -1)
{
aHitObject = ivec4 (aTriIndex.x, // vertex 0
aTriIndex.y, // vertex 1
aTriIndex.z, // vertex 2
aTriIndex.w); // material
theTrsfId = aTrsfId;
}
}
toContinue = aHead >= 0;
if (toContinue)
aNode = Stack[aHead--];
}
else // if inner node
{
float aTimeOut;
float aTimeLft;
float aTimeRgh;
vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
vec3 aTimeMax = max (aTime0, aTime1);
vec3 aTimeMin = min (aTime0, aTime1);
aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theHit.Time);
aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
aTimeMax = max (aTime0, aTime1);
aTimeMin = min (aTime0, aTime1);
aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theHit.Time);
if (bool(aHitLft & aHitRgh))
{
aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
}
else
{
if (bool(aHitLft | aHitRgh))
{
aNode = bool(aHitLft) ? aData.y : aData.z;
}
else
{
toContinue = aHead >= 0;
if (toContinue)
aNode = Stack[aHead--];
}
}
}
}
return aHitObject;
}
// =======================================================================
// function : SceneAnyHit
// purpose : Finds intersection with any scene triangle
// =======================================================================
float SceneAnyHit (in SRay theRay, in vec3 theInverse, in float theDistance)
{
int aHead = -1; // stack pointer
int aNode = 0; // node to visit
float aFactor = 1.f;
for (bool toContinue = true; toContinue;)
{
ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
if (aData.x != 0) // if leaf node
{
// fetch object transformation
int aTrsfId = (aData.x - 1) * 4;
vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0);
vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1);
vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2);
vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, aTrsfId + 3);
SRay aTrsfRay = SRay (
MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
aTrsfInverse = mix (-aTrsfInverse, aTrsfInverse, step (ZERO, aTrsfRay.Direct));
#ifdef TRANSPARENT_SHADOWS
aFactor *= ObjectAnyHit (
aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
toContinue = aHead >= 0 && aFactor >= 0.1f;
#else
aFactor = ObjectAnyHit (
aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
toContinue = aHead >= 0 && aFactor != 0.0f;
#endif
if (toContinue)
aNode = Stack[aHead--];
}
else // if inner node
{
float aTimeOut;
float aTimeLft;
float aTimeRgh;
vec3 aNodeMinLft = texelFetch (uSceneMinPointTexture, aData.y).xyz;
vec3 aNodeMaxLft = texelFetch (uSceneMaxPointTexture, aData.y).xyz;
vec3 aNodeMinRgh = texelFetch (uSceneMinPointTexture, aData.z).xyz;
vec3 aNodeMaxRgh = texelFetch (uSceneMaxPointTexture, aData.z).xyz;
vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
vec3 aTimeMax = max (aTime0, aTime1);
vec3 aTimeMin = min (aTime0, aTime1);
aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
aTimeMax = max (aTime0, aTime1);
aTimeMin = min (aTime0, aTime1);
aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
if (bool(aHitLft & aHitRgh))
{
aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
}
else
{
if (bool(aHitLft | aHitRgh))
{
aNode = bool(aHitLft) ? aData.y : aData.z;
}
else
{
toContinue = aHead >= 0;
if (toContinue)
aNode = Stack[aHead--];
}
}
aStop = aHead; // store current stack pointer
}
}
@ -1013,7 +860,7 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse)
dot (aTrsfRow2, aTexCoord));
vec3 aTexColor = textureLod (
uTextureSamplers[int(aDiffuse.w)], aTexCoord.st, 0.f).rgb;
sampler2D (uTextureSamplers[int(aDiffuse.w)]), aTexCoord.st, 0.f).rgb;
aDiffuse.rgb *= aTexColor;
aAmbient.rgb *= aTexColor;