#ifdef ADAPTIVE_SAMPLING
#extension GL_ARB_shader_image_load_store : require
+#endif
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
#extension GL_NV_shader_atomic_float : require
#endif
uniform samplerBuffer uRaytraceMaterialTexture;
//! Texture buffer of light source properties.
uniform samplerBuffer uRaytraceLightSrcTexture;
-//! Environment map texture.
-uniform sampler2D uEnvironmentMapTexture;
+
+#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 ADAPTIVE_SAMPLING
//! OpenGL image used for accumulating rendering result.
- volatile restrict layout(size1x32) uniform image2D uRenderImage;
+ volatile restrict layout(r32f) uniform image2D uRenderImage;
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
//! OpenGL image storing offsets of sampled pixels blocks.
- coherent restrict layout(size2x32) uniform iimage2D uOffsetImage;
+ 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
//=======================================================================
vec4 BackgroundColor()
{
-#ifdef ADAPTIVE_SAMPLING
+#ifdef ADAPTIVE_SAMPLING_ATOMIC
ivec2 aFragCoord = ivec2 (gl_FragCoord.xy);
- ivec2 aTileXY = imageLoad (uOffsetImage, ivec2 (aFragCoord.x / BLOCK_SIZE,
- aFragCoord.y / BLOCK_SIZE)).xy;
+ ivec2 aTileXY = imageLoad (uOffsetImage, aFragCoord / uTileSize).xy * uTileSize;
- aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, BLOCK_SIZE);
+ aTileXY.y += aFragCoord.y % min (uWinSizeY - aTileXY.y, uTileSize.y);
return mix (uBackColorBot, uBackColorTop, float (aTileXY.y) / uWinSizeY);
/////////////////////////////////////////////////////////////////////////////////////////
// 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);
+
+#else
+
+ vec2 aPixel = uEyeSize * (thePixel - vec2 (0.5f)) * 2.f;
+
+ 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
}
// =======================================================================
ivec4 SubData;
};
-#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)
+#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 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 : SceneNearestHit
// purpose : Finds intersection with nearest scene triangle
// =======================================================================
-ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
+STriangle SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)
{
- ivec4 aTriIndex = INALID_HIT;
+ STriangle aTriangle = STriangle (INVALID_HIT, vec3[](vec3(0.0), vec3(0.0), vec3(0.0)));
int aNode = 0; // node to traverse
int aHead = -1; // pointer of stack
float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aHitTimes.x = mix (MAXFLOAT, aTimeEnter,
- aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f);
+ aHitTimes.x = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT;
aTimeMax = max (aNodeMin1, aNodeMax1);
aTimeMin = min (aNodeMin1, aNodeMax1);
aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aHitTimes.y = mix (MAXFLOAT, aTimeEnter,
- aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f);
+ aHitTimes.y = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT;
aTimeMax = max (aNodeMin2, aNodeMax2);
aTimeMin = min (aNodeMin2, aNodeMax2);
aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aHitTimes.z = mix (MAXFLOAT, aTimeEnter,
- aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 1);
+ aHitTimes.z = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 1) ? aTimeEnter : MAXFLOAT;
aTimeMax = max (aNodeMin3, aNodeMax3);
aTimeMin = min (aNodeMin3, aNodeMax3);
aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aHitTimes.w = mix (MAXFLOAT, aTimeEnter,
- aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 2);
+ aHitTimes.w = (aTimeEnter <= aTimeLeave && aTimeEnter <= theHit.Time && aTimeLeave >= 0.f && aData.z > 2) ? aTimeEnter : MAXFLOAT;
ivec4 aChildren = ivec4 (0, 1, 2, 3);
for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)
{
- ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
+ ivec4 aTriIndex = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));
+ vec3 aPoints[3];
- 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;
+ 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;
- IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal);
+ IntersectTriangle (aSubTree.TrsfRay, aPoints[0], aPoints[1], aPoints[2], aTimeUV, aNormal);
if (aTimeUV.x < theHit.Time)
{
- aTriIndex = aTriangle;
+ aTriangle.TriIndex = aTriIndex;
+ for (int i = 0; i < 3; ++i)
+ {
+ aTriangle.Points[i] = aPoints[i];
+ }
theTrsfId = TRS_OFFSET (aSubTree);
}
}
- return aTriIndex;
+ return aTriangle;
}
// =======================================================================
float aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
float aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aHitTimes.x = mix (MAXFLOAT, aTimeEnter,
- aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f);
+ aHitTimes.x = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT;
aTimeMax = max (aNodeMin1, aNodeMax1);
aTimeMin = min (aNodeMin1, aNodeMax1);
aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aHitTimes.y = mix (MAXFLOAT, aTimeEnter,
- aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f);
+ aHitTimes.y = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f) ? aTimeEnter : MAXFLOAT;
aTimeMax = max (aNodeMin2, aNodeMax2);
aTimeMin = min (aNodeMin2, aNodeMax2);
aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aHitTimes.z = mix (MAXFLOAT, aTimeEnter,
- aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 1);
+ aHitTimes.z = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 1) ? aTimeEnter : MAXFLOAT;
aTimeMax = max (aNodeMin3, aNodeMax3);
aTimeMin = min (aNodeMin3, aNodeMax3);
aTimeLeave = min (aTimeMax.x, min (aTimeMax.y, aTimeMax.z));
aTimeEnter = max (aTimeMin.x, max (aTimeMin.y, aTimeMin.z));
- aHitTimes.w = mix (MAXFLOAT, aTimeEnter,
- aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 2);
+ aHitTimes.w = (aTimeEnter <= aTimeLeave && aTimeEnter <= theDistance && aTimeLeave >= 0.f && aData.z > 2) ? aTimeEnter : MAXFLOAT;
ivec4 aChildren = ivec4 (0, 1, 2, 3);
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
// 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 uSphereMapEnabled == 0 ?
- vec4 (0.f, 0.f, 0.f, 1.f) : textureLod (uEnvironmentMapTexture, theTexCoord, 0.f);
+ 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;
}
// =======================================================================
int aTrsfId;
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, aTrsfId);
+ 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
{
aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),
dot (aTrsfRow2, aTexCoord));
- vec3 aTexColor = textureLod (
- sampler2D (uTextureSamplers[int(aDiffuse.w)]), aTexCoord.st, 0.f).rgb;
+ vec4 aTexColor = textureLod (
+ sampler2D (uTextureSamplers[int(aDiffuse.w)]), aTexCoord.st, 0.f);
+
+ aDiffuse.rgb *= aTexColor.rgb;
+ aAmbient.rgb *= aTexColor.rgb;
- aDiffuse.rgb *= aTexColor;
- aAmbient.rgb *= aTexColor;
+ // keep refractive index untouched (Z component)
+ aOpacity.xy = vec2 (aTexColor.w * aOpacity.x, 1.0f - aTexColor.w * aOpacity.x);
}
#endif
if (aOpacity.x != 1.0f)
{
aWeight *= aOpacity.y;
+ aRefractionIdx = aOpacity.z;
if (aOpacity.z != 1.0f)
{