+#ifdef ADAPTIVE_SAMPLING
+ #extension GL_ARB_shader_image_load_store : require
+#endif
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
+ #extension GL_NV_shader_atomic_float : require
+#endif
+
#ifdef USE_TEXTURES
#extension GL_ARB_bindless_texture : require
#endif
//! Inverse model-view-projection matrix.
uniform mat4 uUnviewMat;
+//! Model-view-projection matrix.
+uniform mat4 uViewMat;
+
//! Texture buffer of data records of bottom-level BVH nodes.
uniform isamplerBuffer uSceneNodeInfoTexture;
//! Texture buffer of minimum points of bottom-level BVH nodes.
uniform samplerBuffer uRaytraceMaterialTexture;
//! Texture buffer of light source properties.
uniform samplerBuffer uRaytraceLightSrcTexture;
-//! Environment map texture.
-uniform sampler2D uEnvironmentMapTexture;
-//! Input pre-raytracing image rendered by OpenGL.
-uniform sampler2D uOpenGlColorTexture;
-//! Input pre-raytracing depth image rendered by OpenGL.
-uniform sampler2D uOpenGlDepthTexture;
+#ifdef BACKGROUND_CUBEMAP
+ //! Environment cubemap texture.
+ uniform samplerCube uEnvMapTexture;
+ //! Coefficient of Y controlling horizontal flip of cubemap
+ uniform int uYCoeff;
+ //! Coefficient of Z controlling vertical flip of cubemap
+ uniform int uZCoeff;
+#else
+ //! Environment map texture.
+ uniform sampler2D uEnvMapTexture;
+#endif
//! Total number of light sources.
uniform int uLightCount;
uniform int uShadowsEnabled;
//! Enables/disables specular reflections.
uniform int uReflectEnabled;
-//! Enables/disables spherical environment map.
-uniform int uSphereMapEnabled;
+//! Enables/disables environment map lighting.
+uniform int uEnvMapEnabled;
//! Enables/disables environment map background.
-uniform int uSphereMapForBack;
+uniform int uEnvMapForBack;
//! Radius of bounding sphere of the scene.
uniform float uSceneRadius;
#ifdef USE_TEXTURES
//! Unique 64-bit handles of OpenGL textures.
- uniform sampler2D uTextureSamplers[MAX_TEX_NUMBER];
+ uniform uvec2 uTextureSamplers[MAX_TEX_NUMBER];
+#endif
+
+#ifdef ADAPTIVE_SAMPLING
+ //! OpenGL image used for accumulating rendering result.
+ volatile restrict layout(r32f) uniform image2D uRenderImage;
+
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
+ //! OpenGL image storing offsets of sampled pixels blocks.
+ coherent restrict layout(rg32i) uniform iimage2D uOffsetImage;
+#else
+ //! OpenGL image defining per-tile amount of samples.
+ volatile restrict layout(r32i) uniform iimage2D uTilesImage;
+#endif
+
+ //! Screen space tile size.
+ uniform ivec2 uTileSize;
#endif
//! Top color of gradient background.
//! Bottom color of gradient background.
uniform vec4 uBackColorBot = vec4 (0.0);
+//! Aperture radius of camera used for depth-of-field
+uniform float uApertureRadius = 0.f;
+
+//! Focal distance of camera used for depth-of field
+uniform float uFocalPlaneDist = 10.f;
+
+//! Camera position used for projective mode
+uniform vec3 uEyeOrig;
+
+//! Camera view direction used for projective mode
+uniform vec3 uEyeView;
+
+//! Camera's screen vertical direction used for projective mode
+uniform vec3 uEyeVert;
+
+//! Camera's screen horizontal direction used for projective mode
+uniform vec3 uEyeSide;
+
+//! Camera's screen size used for projective mode
+uniform vec2 uEyeSize;
+
/////////////////////////////////////////////////////////////////////////////////////////
// Specific data types
vec3 Normal;
};
+//! Stores triangle's vertex indexes and vertexes itself
+struct STriangle
+{
+ ivec4 TriIndex;
+
+ vec3 Points[3];
+};
+
/////////////////////////////////////////////////////////////////////////////////////////
// Some useful constants
#define AXIS_Y vec3 (0.0f, 1.0f, 0.0f)
#define AXIS_Z vec3 (0.0f, 0.0f, 1.0f)
-#define M_PI 3.14159265f
+#define M_PI 3.141592653f
+#define M_2_PI 6.283185307f
+#define M_PI_2 1.570796327f
#define LUMA vec3 (0.2126f, 0.7152f, 0.0722f)
// purpose : Applies hash function by Thomas Wang to randomize seeds
// (see http://www.burtleburtle.net/bob/hash/integer.html)
// =======================================================================
-void SeedRand (in int theSeed, in int theSizeX)
+void SeedRand (in int theSeed, in int theSizeX, in int theRadius)
{
- RandState = uint (int (gl_FragCoord.y) * theSizeX + int (gl_FragCoord.x) + theSeed);
+ RandState = uint (int (gl_FragCoord.y) / theRadius * theSizeX + int (gl_FragCoord.x) / theRadius + theSeed);
RandState = (RandState + 0x479ab41du) + (RandState << 8);
RandState = (RandState ^ 0xe4aa10ceu) ^ (RandState >> 5);
// =======================================================================
// function : RandFloat
-// purpose : Generates a random float in [0, 1) range
+// purpose : Generates a random float in 0 <= x < 1 range
// =======================================================================
float RandFloat()
{
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);
}
// =======================================================================
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);
}
//=======================================================================
//=======================================================================
vec4 BackgroundColor()
{
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
+
+ ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);
+
+ ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;
+
+ aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, uTileSize.y);
+
+ return mix (uBackColorBot, uBackColorTop, float (aTileXY.y) / uWinSizeY);
+
+#else
+
return mix (uBackColorBot, uBackColorTop, vPixel.y);
+
+#endif
}
/////////////////////////////////////////////////////////////////////////////////////////
// Functions for compute ray-object intersection
+//=======================================================================
+// function : sampleUniformDisk
+// purpose :
+//=======================================================================
+vec2 sampleUniformDisk ()
+{
+ vec2 aPoint;
+
+ float aKsi1 = 2.f * RandFloat () - 1.f;
+ float aKsi2 = 2.f * RandFloat () - 1.f;
+
+ if (aKsi1 > -aKsi2)
+ {
+ if (aKsi1 > aKsi2)
+ aPoint = vec2 (aKsi1, (M_PI / 4.f) * (0.f + aKsi2 / aKsi1));
+ else
+ aPoint = vec2 (aKsi2, (M_PI / 4.f) * (2.f - aKsi1 / aKsi2));
+ }
+ else
+ {
+ if (aKsi1 < aKsi2)
+ aPoint = vec2 (-aKsi1, (M_PI / 4.f) * (4.f + aKsi2 / aKsi1));
+ else
+ aPoint = vec2 (-aKsi2, (M_PI / 4.f) * (6.f - aKsi1 / aKsi2));
+ }
+
+ return vec2 (sin (aPoint.y), cos (aPoint.y)) * aPoint.x;
+}
+
// =======================================================================
// function : GenerateRay
// purpose :
// =======================================================================
SRay GenerateRay (in vec2 thePixel)
{
+#ifndef DEPTH_OF_FIELD
+
vec3 aP0 = mix (uOriginLB, uOriginRB, thePixel.x);
vec3 aP1 = mix (uOriginLT, uOriginRT, thePixel.x);
vec3 aDirection = normalize (mix (aD0, aD1, thePixel.y));
return SRay (mix (aP0, aP1, thePixel.y), aDirection);
-}
-// =======================================================================
-// function : ComputeOpenGlDepth
-// purpose :
-// =======================================================================
-float ComputeOpenGlDepth (in SRay theRay)
-{
- // a depth in range [0,1]
- float anOpenGlDepth = texelFetch (uOpenGlDepthTexture, ivec2 (gl_FragCoord.xy), 0).r;
- // pixel point in NDC-space [-1,1]
- vec4 aPoint = vec4 (2.0f * vPixel.x - 1.0f,
- 2.0f * vPixel.y - 1.0f,
- 2.0f * anOpenGlDepth - 1.0f,
- 1.0f);
- vec4 aFinal = uUnviewMat * aPoint;
- aFinal.xyz *= 1.f / aFinal.w;
-
- return (anOpenGlDepth < 1.f) ? length (aFinal.xyz - theRay.Origin) : MAXFLOAT;
-}
+#else
-// =======================================================================
-// function : ComputeOpenGlColor
-// purpose :
-// =======================================================================
-vec4 ComputeOpenGlColor()
-{
- vec4 anOpenGlColor = texelFetch (uOpenGlColorTexture, ivec2 (gl_FragCoord.xy), 0);
- // During blending with factors GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA (for text and markers)
- // the alpha channel (written in the color buffer) was squared.
- anOpenGlColor.a = 1.f - sqrt (anOpenGlColor.a);
+ vec2 aPixel = uEyeSize * (thePixel - vec2 (0.5f)) * 2.f;
- return anOpenGlColor;
+ vec2 aAperturePnt = sampleUniformDisk () * uApertureRadius;
+
+ vec3 aLocalDir = normalize (vec3 (
+ aPixel * uFocalPlaneDist - aAperturePnt, uFocalPlaneDist));
+
+ vec3 aOrigin = uEyeOrig +
+ uEyeSide * aAperturePnt.x +
+ uEyeVert * aAperturePnt.y;
+
+ vec3 aDirect = uEyeView * aLocalDir.z +
+ uEyeSide * aLocalDir.x +
+ uEyeVert * aLocalDir.y;
+
+ return SRay (aOrigin, aDirect);
+
+#endif
}
// =======================================================================
// function : IntersectTriangle
// purpose : Computes ray-triangle intersection (branchless version)
// =======================================================================
-float IntersectTriangle (in SRay theRay,
- in vec3 thePnt0,
- in vec3 thePnt1,
- in vec3 thePnt2,
- out vec2 theUV,
- out vec3 theNorm)
+void IntersectTriangle (in SRay theRay,
+ in vec3 thePnt0,
+ in vec3 thePnt1,
+ in vec3 thePnt2,
+ out vec3 theUVT,
+ out vec3 theNorm)
{
+ vec3 aToTrg = thePnt0 - theRay.Origin;
+
vec3 aEdge0 = thePnt1 - thePnt0;
vec3 aEdge1 = thePnt0 - thePnt2;
theNorm = cross (aEdge1, aEdge0);
- vec3 aEdge2 = (1.0f / dot (theNorm, theRay.Direct)) * (thePnt0 - theRay.Origin);
+ vec3 theVect = cross (theRay.Direct, aToTrg);
+
+ theUVT = vec3 (dot (theNorm, aToTrg),
+ dot (theVect, aEdge1),
+ dot (theVect, aEdge0)) * (1.f / dot (theNorm, theRay.Direct));
- float aTime = dot (theNorm, aEdge2);
+ theUVT.x = any (lessThan (theUVT, ZERO)) || (theUVT.y + theUVT.z) > 1.f ? MAXFLOAT : theUVT.x;
+}
- vec3 theVec = cross (theRay.Direct, aEdge2);
+#define EMPTY_ROOT ivec4(0)
- theUV.x = dot (theVec, aEdge1);
- theUV.y = dot (theVec, aEdge0);
+//! Utility structure containing information about
+//! currently traversing sub-tree of scene's BVH.
+struct SSubTree
+{
+ //! Transformed ray.
+ SRay TrsfRay;
- return bool (int(aTime >= 0.0f) &
- int(theUV.x >= 0.0f) &
- int(theUV.y >= 0.0f) &
- int(theUV.x + theUV.y <= 1.0f)) ? aTime : MAXFLOAT;
-}
+ //! Inversed ray direction.
+ vec3 Inverse;
+
+ //! Parameters of sub-root node.
+ ivec4 SubData;
+};
+
+#define MATERIAL_AMBN(index) (19 * index + 0)
+#define MATERIAL_DIFF(index) (19 * index + 1)
+#define MATERIAL_SPEC(index) (19 * index + 2)
+#define MATERIAL_EMIS(index) (19 * index + 3)
+#define MATERIAL_REFL(index) (19 * index + 4)
+#define MATERIAL_REFR(index) (19 * index + 5)
+#define MATERIAL_TRAN(index) (19 * index + 6)
+#define MATERIAL_TRS1(index) (19 * index + 7)
+#define MATERIAL_TRS2(index) (19 * index + 8)
+#define MATERIAL_TRS3(index) (19 * index + 9)
+
+#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
//! Identifies the absence of intersection.
-#define INALID_HIT ivec4 (-1)
+#define INVALID_HIT ivec4 (-1)
//! Global stack shared between traversal functions.
int Stack[STACK_SIZE];
// =======================================================================
-// function : ObjectNearestHit
-// purpose : Finds intersection with nearest object triangle
+// function : pop
+// purpose :
// =======================================================================
-ivec4 ObjectNearestHit (in int theBVHOffset, in int theVrtOffset, in int theTrgOffset,
- in SRay theRay, in vec3 theInverse, inout SIntersect theHit, in int theSentinel)
+int pop (inout int theHead)
{
- int aHead = theSentinel; // stack pointer
- int aNode = theBVHOffset; // node to visit
+ int aData = Stack[theHead];
- ivec4 aTriIndex = INALID_HIT;
+ int aMask = aData >> 26;
+ int aNode = aMask & 0x3;
- bool toContinue = true;
+ aMask >>= 2;
- while (toContinue)
+ if ((aMask & 0x3) == aNode)
{
- ivec3 aData = texelFetch (uSceneNodeInfoTexture, aNode).xyz;
-
- if (aData.x == 0) // if inner node
- {
- float aTimeOut;
- float aTimeLft;
- float aTimeRgh;
-
- aData.y += theBVHOffset;
- aData.z += theBVHOffset;
-
- 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 aTimeMax = max (aTime0, aTime1);
- vec3 aTimeMin = min (aTime0, aTime1);
-
- aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
- aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
-
- 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);
-
- 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 != theSentinel);
-
- if (toContinue)
- aNode = Stack[aHead--];
- }
- }
- }
- else // if leaf node
- {
- vec3 aNormal;
- vec2 aParams;
-
- for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
- {
- ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
-
- vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += theVrtOffset).xyz;
- vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += theVrtOffset).xyz;
- vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += theVrtOffset).xyz;
-
- float aTime = IntersectTriangle (theRay,
- aPoint0,
- aPoint1,
- aPoint2,
- aParams,
- aNormal);
-
- if (aTime < theHit.Time)
- {
- aTriIndex = aTriangle;
-
- theHit = SIntersect (aTime, aParams, aNormal);
- }
- }
-
- toContinue = (aHead != theSentinel);
+ --theHead;
+ }
+ else
+ {
+ aMask |= (aMask << 2) & 0x30;
- if (toContinue)
- aNode = Stack[aHead--];
- }
+ Stack[theHead] = (aData & 0x03FFFFFF) | (aMask << 26);
}
- return aTriIndex;
+ return (aData & 0x03FFFFFF) + aNode;
}
-#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 : SceneNearestHit
+// purpose : Finds intersection with nearest 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)
+STriangle SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
{
- int aHead = theSentinel; // stack pointer
- int aNode = theBVHOffset; // node to visit
+ STriangle aTriangle = STriangle (INVALID_HIT, vec3[](vec3(0.0), vec3(0.0), vec3(0.0)));
-#ifdef TRANSPARENT_SHADOWS
- float aFactor = 1.0f;
-#endif
+ 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);
- while (true)
+ for (bool toContinue = true; toContinue; /* none */)
{
ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
if (aData.x == 0) // if inner node
{
- float aTimeOut;
- float aTimeLft;
- float aTimeRgh;
+ aData.y += BVH_OFFSET (aSubTree);
+
+ vec4 aHitTimes = vec4 (MAXFLOAT,
+ MAXFLOAT,
+ MAXFLOAT,
+ MAXFLOAT);
+
+ vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse;
+
+ vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
+
+ vec3 aTimeMax = max (aNodeMin0, aNodeMax0);
+ vec3 aTimeMin = min (aNodeMin0, aNodeMax0);
+
+ float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
+ float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
+
+ aHitTimes.x = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT;
- aData.y += theBVHOffset;
- aData.z += theBVHOffset;
+ aTimeMax = max (aNodeMin1, aNodeMax1);
+ aTimeMin = min (aNodeMin1, aNodeMax1);
- 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;
+ aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
+ aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
- vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
+ aHitTimes.y = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT;
- vec3 aTimeMax = max (aTime0, aTime1);
- vec3 aTimeMin = min (aTime0, aTime1);
+ aTimeMax = max (aNodeMin2, aNodeMax2);
+ aTimeMin = min (aNodeMin2, aNodeMax2);
- aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
- aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
+ aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
+ aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
- aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
+ aHitTimes.z = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 1) ? aTimeEnter : MAXFLOAT;
- int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theDistance);
+ aTimeMax = max (aNodeMin3, aNodeMax3);
+ aTimeMin = min (aNodeMin3, aNodeMax3);
- aTimeMax = max (aTime0, aTime1);
- aTimeMin = min (aTime0, aTime1);
+ aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
+ aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
- aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
+ aHitTimes.w = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 2) ? aTimeEnter : MAXFLOAT;
- int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theDistance);
+ ivec4 aChildren = ivec4 (0, 1, 2, 3);
- if (bool(aHitLft & aHitRgh))
+ aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy;
+ aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy;
+ aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw;
+ aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw;
+ aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz;
+ aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz;
+ aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw;
+ aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw;
+ aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz;
+ aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz;
+
+ if (aHitTimes.x != MAXFLOAT)
{
- aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
+ int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2
+ | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y);
+
+ if (aHitTimes.y != MAXFLOAT)
+ Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26;
- Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
+ aNode = aData.y + aChildren.x;
}
else
{
- if (bool(aHitLft | aHitRgh))
+ toContinue = (aHead >= 0);
+
+ if (aHead == aStop) // go to top-level BVH
{
- aNode = bool(aHitLft) ? aData.y : aData.z;
+ aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
}
- else
- {
-#ifdef TRANSPARENT_SHADOWS
- if (aHead == theSentinel)
- return aFactor;
-#else
- if (aHead == theSentinel)
- return 1.0f;
-#endif
- aNode = Stack[aHead--];
- }
+ if (aHead >= 0)
+ aNode = pop (aHead);
}
}
- else // if leaf node
+ else if (aData.x < 0) // leaf node (contains triangles)
{
vec3 aNormal;
- vec2 aParams;
+ vec3 aTimeUV;
for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
{
- ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + theTrgOffset);
+ ivec4 aTriIndex = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
+ vec3 aPoints[3];
- vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x + theVrtOffset).xyz;
- vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y + theVrtOffset).xyz;
- vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z + theVrtOffset).xyz;
+ aPoints[0] = texelFetch (uGeometryVertexTexture, aTriIndex.x += VRT_OFFSET (aSubTree)).xyz;
+ aPoints[1] = texelFetch (uGeometryVertexTexture, aTriIndex.y += VRT_OFFSET (aSubTree)).xyz;
+ aPoints[2] = texelFetch (uGeometryVertexTexture, aTriIndex.z += VRT_OFFSET (aSubTree)).xyz;
- float aTime = IntersectTriangle (theRay,
- aPoint0,
- aPoint1,
- aPoint2,
- aParams,
- aNormal);
+ IntersectTriangle (aSubTree.TrsfRay, aPoints[0], aPoints[1], aPoints[2], aTimeUV, aNormal);
-#ifdef TRANSPARENT_SHADOWS
- if (aTime < theDistance)
+ if (aTimeUV.x < theHit.Time)
{
- aFactor *= 1.0f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
+ aTriangle.TriIndex = aTriIndex;
+ for (int i = 0; i < 3; ++i)
+ {
+ aTriangle.Points[i] = aPoints[i];
+ }
+
+ theTrsfId = TRS_OFFSET (aSubTree);
+
+ theHit = SIntersect (aTimeUV.x, aTimeUV.yz, aNormal);
}
-#else
- if (aTime < theDistance)
- return 0.0f;
-#endif
}
-#ifdef TRANSPARENT_SHADOWS
- if (aHead == theSentinel || aFactor < 0.1f)
- return aFactor;
-#else
- if (aHead == theSentinel)
- return 1.0f;
-#endif
+ toContinue = (aHead >= 0);
- aNode = Stack[aHead--];
+ if (aHead == aStop) // go to top-level BVH
+ {
+ aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
+ }
+
+ if (aHead >= 0)
+ aNode = pop (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
}
}
-#ifdef TRANSPARENT_SHADOWS
- return aFactor;
-#else
- return 1.0f;
-#endif
+ return aTriangle;
}
// =======================================================================
-// function : SceneNearestHit
-// purpose : Finds intersection with nearest scene triangle
+// function : SceneAnyHit
+// purpose : Finds intersection with any scene triangle
// =======================================================================
-ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theObjectId)
+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;
- ivec4 aHitObject = INALID_HIT;
+ int aNode = 0; // node to traverse
+ int aHead = -1; // pointer of stack
+ int aStop = -1; // BVH level switch
- while (true)
+ SSubTree aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
+
+ for (bool toContinue = true; toContinue; /* none */)
{
ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
- if (aData.x != 0) // if leaf node
+ if (aData.x == 0) // if inner node
{
- vec3 aNodeMin = texelFetch (uSceneMinPointTexture, aNode).xyz;
- vec3 aNodeMax = texelFetch (uSceneMaxPointTexture, aNode).xyz;
-
- vec3 aTime0 = (aNodeMin - theRay.Origin) * theInverse;
- vec3 aTime1 = (aNodeMax - theRay.Origin) * theInverse;
-
- vec3 aTimes = min (aTime0, aTime1);
-
- if (max (aTimes.x, max (aTimes.y, aTimes.z)) < theHit.Time)
- {
- // fetch object transformation
- int anObjectId = aData.x - 1;
+ aData.y += BVH_OFFSET (aSubTree);
- vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
- vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
- vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
- vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
+ vec4 aHitTimes = vec4 (MAXFLOAT,
+ MAXFLOAT,
+ MAXFLOAT,
+ MAXFLOAT);
- SRay aTrsfRay = SRay (
- MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
- MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
+ vec3 aRayOriginInverse = -aSubTree.TrsfRay.Origin * aSubTree.Inverse;
- vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
+ vec3 aNodeMin0 = texelFetch (uSceneMinPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMin1 = texelFetch (uSceneMinPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMin2 = texelFetch (uSceneMinPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMin3 = texelFetch (uSceneMinPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMax0 = texelFetch (uSceneMaxPointTexture, aData.y + 0).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMax1 = texelFetch (uSceneMaxPointTexture, aData.y + 1).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMax2 = texelFetch (uSceneMaxPointTexture, aData.y + min (2, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
+ vec3 aNodeMax3 = texelFetch (uSceneMaxPointTexture, aData.y + min (3, aData.z)).xyz * aSubTree.Inverse + aRayOriginInverse;
- aTrsfInverse = mix (-aTrsfInverse, aTrsfInverse, step (ZERO, aTrsfRay.Direct));
+ vec3 aTimeMax = max (aNodeMin0, aNodeMax0);
+ vec3 aTimeMin = min (aNodeMin0, aNodeMax0);
- ivec4 aTriIndex = ObjectNearestHit (
- aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theHit, aHead);
+ float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
+ float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- if (aTriIndex.x != -1)
- {
- aHitObject = ivec4 (aTriIndex.x, // vertex 0
- aTriIndex.y, // vertex 1
- aTriIndex.z, // vertex 2
- aTriIndex.w); // material
+ aHitTimes.x = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT;
- theObjectId = anObjectId;
- }
- }
+ aTimeMax = max (aNodeMin1, aNodeMax1);
+ aTimeMin = min (aNodeMin1, aNodeMax1);
- if (aHead < 0)
- return aHitObject;
+ aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
+ aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aNode = Stack[aHead--];
- }
- else // if inner node
- {
- float aTimeOut;
- float aTimeLft;
- float aTimeRgh;
+ aHitTimes.y = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT;
- 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;
+ aTimeMax = max (aNodeMin2, aNodeMax2);
+ aTimeMin = min (aNodeMin2, aNodeMax2);
- vec3 aTime0 = (aNodeMinLft - theRay.Origin) * theInverse;
- vec3 aTime1 = (aNodeMaxLft - theRay.Origin) * theInverse;
+ aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
+ aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- vec3 aTimeMax = max (aTime0, aTime1);
- vec3 aTimeMin = min (aTime0, aTime1);
+ aHitTimes.z = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 1) ? aTimeEnter : MAXFLOAT;
- aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
- aTimeLft = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
+ aTimeMax = max (aNodeMin3, aNodeMax3);
+ aTimeMin = min (aNodeMin3, aNodeMax3);
- int aHitLft = int(aTimeLft <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeLft <= theHit.Time);
+ aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
+ aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aTime0 = (aNodeMinRgh - theRay.Origin) * theInverse;
- aTime1 = (aNodeMaxRgh - theRay.Origin) * theInverse;
+ aHitTimes.w = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 2) ? aTimeEnter : MAXFLOAT;
- aTimeMax = max (aTime0, aTime1);
- aTimeMin = min (aTime0, aTime1);
+ ivec4 aChildren = ivec4 (0, 1, 2, 3);
- aTimeOut = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
- aTimeRgh = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
+ aChildren.xy = aHitTimes.y < aHitTimes.x ? aChildren.yx : aChildren.xy;
+ aHitTimes.xy = aHitTimes.y < aHitTimes.x ? aHitTimes.yx : aHitTimes.xy;
+ aChildren.zw = aHitTimes.w < aHitTimes.z ? aChildren.wz : aChildren.zw;
+ aHitTimes.zw = aHitTimes.w < aHitTimes.z ? aHitTimes.wz : aHitTimes.zw;
+ aChildren.xz = aHitTimes.z < aHitTimes.x ? aChildren.zx : aChildren.xz;
+ aHitTimes.xz = aHitTimes.z < aHitTimes.x ? aHitTimes.zx : aHitTimes.xz;
+ aChildren.yw = aHitTimes.w < aHitTimes.y ? aChildren.wy : aChildren.yw;
+ aHitTimes.yw = aHitTimes.w < aHitTimes.y ? aHitTimes.wy : aHitTimes.yw;
+ aChildren.yz = aHitTimes.z < aHitTimes.y ? aChildren.zy : aChildren.yz;
+ aHitTimes.yz = aHitTimes.z < aHitTimes.y ? aHitTimes.zy : aHitTimes.yz;
- int aHitRgh = int(aTimeRgh <= aTimeOut) & int(aTimeOut >= 0.0f) & int(aTimeRgh <= theHit.Time);
-
- if (bool(aHitLft & aHitRgh))
+ if (aHitTimes.x != MAXFLOAT)
{
- aNode = (aTimeLft < aTimeRgh) ? aData.y : aData.z;
+ int aHitMask = (aHitTimes.w != MAXFLOAT ? aChildren.w : aChildren.z) << 2
+ | (aHitTimes.z != MAXFLOAT ? aChildren.z : aChildren.y);
+
+ if (aHitTimes.y != MAXFLOAT)
+ Stack[++aHead] = aData.y | (aHitMask << 2 | aChildren.y) << 26;
- Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
+ aNode = aData.y + aChildren.x;
}
else
{
- if (bool(aHitLft | aHitRgh))
+ toContinue = (aHead >= 0);
+
+ if (aHead == aStop) // go to top-level BVH
{
- aNode = bool(aHitLft) ? aData.y : aData.z;
+ aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
}
- else
- {
- if (aHead < 0)
- return aHitObject;
- aNode = Stack[aHead--];
- }
+ if (aHead >= 0)
+ aNode = pop (aHead);
}
}
- }
+ else if (aData.x < 0) // leaf node
+ {
+ vec3 aNormal;
+ vec3 aTimeUV;
- return aHitObject;
-}
+ for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
+ {
+ ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
-// =======================================================================
-// 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
+ 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;
+
+ IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal);
#ifdef TRANSPARENT_SHADOWS
- float aFactor = 1.0f;
+ if (aTimeUV.x < theDistance)
+ {
+ aFactor *= 1.f - texelFetch (uRaytraceMaterialTexture, MATERIAL_TRAN (aTriangle.w)).x;
+ }
+#else
+ if (aTimeUV.x < theDistance)
+ {
+ aFactor = 0.f;
+ }
#endif
+ }
- while (true)
- {
- ivec4 aData = texelFetch (uSceneNodeInfoTexture, aNode);
-
- if (aData.x != 0) // if leaf node
- {
- // fetch object transformation
- int anObjectId = aData.x - 1;
-
- vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0);
- vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1);
- vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2);
- vec4 aInvTransf3 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 3);
-
- SRay aTrsfRay = SRay (
- MatrixColMultiplyPnt (theRay.Origin, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3),
- MatrixColMultiplyDir (theRay.Direct, aInvTransf0, aInvTransf1, aInvTransf2, aInvTransf3));
+ toContinue = (aHead >= 0) && (aFactor > 0.1f);
- vec3 aTrsfInverse = 1.0f / max (abs (aTrsfRay.Direct), SMALL);
+ if (aHead == aStop) // go to top-level BVH
+ {
+ aStop = -1; aSubTree = SSubTree (theRay, theInverse, EMPTY_ROOT);
+ }
- aTrsfInverse = mix (-aTrsfInverse, aTrsfInverse, step (ZERO, aTrsfRay.Direct));
+ if (aHead >= 0)
+ aNode = pop (aHead);
+ }
+ else if (aData.x > 0) // switch node
+ {
+ aSubTree.SubData = ivec4 (4 * aData.x - 4, aData.yzw); // store BVH sub-root
-#ifdef TRANSPARENT_SHADOWS
- aFactor *= ObjectAnyHit (
- aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
+ 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);
- if (aHead < 0 || aFactor < 0.1f)
- return aFactor;
-#else
- bool isShadow = 0.0f == ObjectAnyHit (
- aData.y, aData.z, aData.w, aTrsfRay, aTrsfInverse, theDistance, aHead);
+ aSubTree.TrsfRay.Direct = MatrixColMultiplyDir (theRay.Direct,
+ aInvTransf0,
+ aInvTransf1,
+ aInvTransf2);
- if (aHead < 0 || isShadow)
- return isShadow ? 0.0f : 1.0f;
-#endif
+ aSubTree.TrsfRay.Origin = MatrixColMultiplyPnt (theRay.Origin,
+ aInvTransf0,
+ aInvTransf1,
+ aInvTransf2,
+ aInvTransf3);
- 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;
+ aSubTree.Inverse = mix (-UNIT, UNIT, step (ZERO, aSubTree.TrsfRay.Direct)) / max (abs (aSubTree.TrsfRay.Direct), SMALL);
- Stack[++aHead] = (aTimeLft < aTimeRgh) ? aData.z : aData.y;
- }
- else
- {
- if (bool(aHitLft | aHitRgh))
- {
- aNode = bool(aHitLft) ? aData.y : aData.z;
- }
- else
- {
-#ifdef TRANSPARENT_SHADOWS
- if (aHead < 0)
- return aFactor;
-#else
- if (aHead < 0)
- return 1.0f;
-#endif
+ aNode = BVH_OFFSET (aSubTree); // go to sub-root node
- aNode = Stack[aHead--];
- }
- }
+ aStop = aHead; // store current stack pointer
}
}
-#ifdef TRANSPARENT_SHADOWS
return aFactor;
-#else
- return 1.0f;
-#endif
}
#define PI 3.1415926f
aPsi * 0.3183098f);
}
+#ifdef BACKGROUND_CUBEMAP
+//! Transform texture coordinates for cubemap lookup.
+vec3 cubemapVectorTransform (in vec3 theVec, in float theRadius)
+{
+ vec3 aVec = theVec.yzx;
+ aVec.y *= float(uYCoeff);
+ aVec.z *= float(uZCoeff);
+ return aVec;
+}
+#endif
+
// =======================================================================
// function : SmoothNormal
// purpose : Interpolates normal across the triangle
aNormal0 * (1.0f - theUV.x - theUV.y));
}
+#define POLYGON_OFFSET_UNIT 0.f
+#define POLYGON_OFFSET_FACTOR 1.f
+#define POLYGON_OFFSET_SCALE 0.006f
+
+// =======================================================================
+// function : PolygonOffset
+// purpose : Computes OpenGL polygon offset
+// =======================================================================
+float PolygonOffset (in vec3 theNormal, in vec3 thePoint)
+{
+ vec4 aProjectedNorm = vec4 (theNormal, -dot (theNormal, thePoint)) * uUnviewMat;
+
+ float aPolygonOffset = POLYGON_OFFSET_UNIT;
+
+ if (aProjectedNorm.z * aProjectedNorm.z > 1e-20f)
+ {
+ aProjectedNorm.xy *= 1.f / aProjectedNorm.z;
+
+ aPolygonOffset += POLYGON_OFFSET_FACTOR * max (abs (aProjectedNorm.x),
+ abs (aProjectedNorm.y));
+ }
+
+ return aPolygonOffset;
+}
+
// =======================================================================
// function : SmoothUV
// purpose : Interpolates UV coordinates across the triangle
// =======================================================================
#ifdef USE_TEXTURES
-vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle)
+vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle, out vec2[3] theUVs)
{
- vec2 aTexCrd0 = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st;
- vec2 aTexCrd1 = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st;
- vec2 aTexCrd2 = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st;
+ theUVs[0] = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st;
+ theUVs[1] = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st;
+ theUVs[2] = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st;
+
+ return theUVs[1] * theUV.x +
+ theUVs[2] * theUV.y +
+ theUVs[0] * (1.0f - theUV.x - theUV.y);
+}
- return aTexCrd1 * theUV.x +
- aTexCrd2 * theUV.y +
- aTexCrd0 * (1.0f - theUV.x - theUV.y);
+vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle)
+{
+ vec2 aUVs[3];
+ return SmoothUV (theUV, theTriangle, aUVs);
}
#endif
// function : FetchEnvironment
// purpose :
// =======================================================================
-vec4 FetchEnvironment (in vec2 theTexCoord)
+vec4 FetchEnvironment (in vec3 theTexCoord, in float theRadius, in bool theIsBackground)
{
- return mix (vec4 (0.0f, 0.0f, 0.0f, 1.0f),
- textureLod (uEnvironmentMapTexture, theTexCoord, 0.0f), float (uSphereMapEnabled));
+ if (uEnvMapEnabled == 0)
+ {
+#ifdef PATH_TRACING
+ return theIsBackground ? vec4 (0.0, 0.0, 0.0, 1.0) : uGlobalAmbient;
+#else
+ return vec4 (0.0, 0.0, 0.0, 1.0);
+#endif
+ }
+
+ vec4 anAmbScale = theIsBackground ? vec4(1.0) : uGlobalAmbient;
+ vec4 anEnvColor =
+#ifdef BACKGROUND_CUBEMAP
+ textureLod (uEnvMapTexture, cubemapVectorTransform (theTexCoord, theRadius), 0.0);
+#else
+ textureLod (uEnvMapTexture, Latlong (theTexCoord, theRadius), 0.0);
+#endif
+ return anEnvColor * anAmbScale;
}
// =======================================================================
vec3 aResult = vec3 (0.0f);
vec4 aWeight = vec4 (1.0f);
- int anObjectId;
+ int aTrsfId;
- float anOpenGlDepth = ComputeOpenGlDepth (theRay);
+ float aRaytraceDepth = MAXFLOAT;
+ float aRefractionIdx = 0.0;
for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)
{
SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);
- ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, anObjectId);
+ ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId).TriIndex;
if (aTriIndex.x == -1)
{
vec4 aColor = vec4 (0.0);
- if (bool(uSphereMapForBack) || aWeight.w == 0.0f /* reflection */)
+ if (bool(uEnvMapForBack) || aWeight.w == 0.0 /* reflection */)
{
- float aTime = IntersectSphere (theRay, uSceneRadius);
+ float aRadius = uSceneRadius;
+ vec3 aTexCoord = vec3 (0.0);
- aColor = FetchEnvironment (Latlong (
- theRay.Direct * aTime + theRay.Origin, uSceneRadius));
+ if (aDepth == 0 || (aRefractionIdx == 1.0 && aWeight.w != 0.0))
+ {
+ vec2 aPixel = uEyeSize * (vPixel - vec2 (0.5)) * 2.0;
+ vec2 anAperturePnt = sampleUniformDisk() * uApertureRadius;
+ vec3 aLocalDir = normalize (vec3 (aPixel * uFocalPlaneDist - anAperturePnt, uFocalPlaneDist));
+ vec3 aDirect = uEyeView * aLocalDir.z +
+ uEyeSide * aLocalDir.x +
+ uEyeVert * aLocalDir.y;
+
+ aTexCoord = aDirect * uSceneRadius;
+ aRadius = length (aTexCoord);
+ }
+ else
+ {
+ float aTime = IntersectSphere (theRay, uSceneRadius);
+ aTexCoord = theRay.Direct * aTime + theRay.Origin;
+ }
+
+ aColor = FetchEnvironment (aTexCoord, aRadius, aWeight.w != 0.0);
}
else
{
- vec4 aGlColor = ComputeOpenGlColor();
- aColor = vec4 (BackgroundColor().rgb * aGlColor.w + ComputeOpenGlColor().rgb, aGlColor.w);
+ aColor = BackgroundColor();
}
- return vec4 (aResult.xyz + aWeight.xyz * aColor.xyz, aWeight.w * aColor.w);
+ aResult += aWeight.xyz * aColor.xyz; aWeight.w *= aColor.w;
+
+ break; // terminate path
}
- vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0).xyz;
- vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1).xyz;
- vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2).xyz;
+ vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTrsfId + 0).xyz;
+ vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTrsfId + 1).xyz;
+ vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTrsfId + 2).xyz;
aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),
dot (aInvTransf1, aHit.Normal),
dot (aInvTransf2, aHit.Normal)));
- // For polygons that are parallel to the screen plane, the depth slope
- // is equal to 1, resulting in small polygon offset. For polygons that
- // that are at a large angle to the screen, the depth slope tends to 1,
- // resulting in a larger polygon offset
- float aPolygonOffset = uSceneEpsilon * EPS_SCALE /
- max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE);
+ theRay.Origin += theRay.Direct * aHit.Time; // intersection point
- if (anOpenGlDepth < aHit.Time + aPolygonOffset)
+ // Evaluate depth on first hit
+ if (aDepth == 0)
{
- vec4 aGlColor = ComputeOpenGlColor();
+ vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);
- aResult += aWeight.xyz * aGlColor.xyz;
- aWeight *= aGlColor.w;
+ float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);
+ aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;
}
- theRay.Origin += theRay.Direct * aHit.Time; // intersection point
-
vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);
aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),
aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),
dot (aTrsfRow2, aTexCoord));
- vec3 aTexColor = textureLod (
- uTextureSamplers[int(aDiffuse.w)], aTexCoord.st, 0.f).rgb;
+ vec4 aTexColor = textureLod (
+ sampler2D (uTextureSamplers[int(aDiffuse.w)]), aTexCoord.st, 0.f);
- aDiffuse.rgb *= aTexColor;
- aAmbient.rgb *= aTexColor;
+ aDiffuse.rgb *= aTexColor.rgb;
+ aAmbient.rgb *= aTexColor.rgb;
+
+ // keep refractive index untouched (Z component)
+ aOpacity.xy = vec2 (aTexColor.w * aOpacity.x, 1.0f - aTexColor.w * aOpacity.x);
}
#endif
if (aVisibility > 0.0f)
{
- vec3 aIntensity = vec3 (texelFetch (
- uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx)));
+ vec3 aIntensity = min (UNIT, vec3 (texelFetch (
+ uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx))));
float aRdotV = dot (reflect (aLight.xyz, aSidedNormal), theRay.Direct);
if (aOpacity.x != 1.0f)
{
aWeight *= aOpacity.y;
+ aRefractionIdx = aOpacity.z;
if (aOpacity.z != 1.0f)
{
theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w);
}
- else
- {
- anOpenGlDepth -= aHit.Time + uSceneEpsilon;
- }
}
else
{
theInverse = 1.0f / max (abs (theRay.Direct), SMALL);
theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct));
-
- anOpenGlDepth = MAXFLOAT; // disable combining image with OpenGL output
}
theRay.Origin += theRay.Direct * uSceneEpsilon;
}
+ gl_FragDepth = aRaytraceDepth;
+
return vec4 (aResult.x,
aResult.y,
aResult.z,