Last active
April 20, 2022 15:03
-
-
Save erichlof/e1fffe6006ef90d376331e300b3a1f2b to your computer and use it in GitHub Desktop.
1-sided Rectangle area lights
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
precision highp float; | |
precision highp int; | |
precision highp sampler2D; | |
uniform sampler2D tTriangleTexture; | |
uniform sampler2D tAABBTexture; | |
#include <pathtracing_uniforms_and_defines> | |
uniform mat4 uLight0_Matrix; | |
uniform mat4 uLight1_Matrix; | |
uniform mat4 uLight0_InvMatrix; | |
uniform mat4 uLight1_InvMatrix; | |
uniform float uFogDensity; | |
uniform float uLight0Power; | |
uniform float uLight1Power; | |
//float InvTextureWidth = 0.000244140625; // (1 / 4096 texture width) | |
//float InvTextureWidth = 0.00048828125; // (1 / 2048 texture width) | |
//float InvTextureWidth = 0.0009765625; // (1 / 1024 texture width) | |
#define INV_TEXTURE_WIDTH 0.00048828125 | |
#define N_RECTANGLES 2 | |
//----------------------------------------------------------------------- | |
vec3 rayOrigin, rayDirection; | |
// recorded intersection data: | |
// vec3 hitNormal, hitEmission, hitColor; | |
vec2 hitUV; | |
// int hitType; | |
// float hitObjectID; | |
bool hitIsModel; | |
struct Rectangle | |
{ | |
vec3 position; | |
vec3 normal; | |
float radiusU; | |
float radiusV; | |
vec3 emission; | |
vec3 color; | |
int type; | |
}; | |
struct Sphere | |
{ | |
float radius; | |
vec3 position; | |
vec3 emission; | |
vec3 color; | |
int type; | |
}; | |
// struct Box { vec3 minCorner; vec3 maxCorner; vec3 emission; vec3 color; int type; }; | |
Rectangle rectangles[N_RECTANGLES]; | |
#include <pathtracing_random_functions> | |
#include <pathtracing_calc_fresnel_reflectance> | |
#include <pathtracing_sphere_intersect> | |
#include <pathtracing_boundingbox_intersect> | |
#include <pathtracing_bvhTriangle_intersect> | |
//#include <pathtracing_rectangle_intersect> | |
vec2 stackLevels[28]; | |
//vec4 boxNodeData0 corresponds to .x = idTriangle, .y = aabbMin.x, .z = aabbMin.y, .w = aabbMin.z | |
//vec4 boxNodeData1 corresponds to .x = idRightChild .y = aabbMax.x, .z = aabbMax.y, .w = aabbMax.z | |
void GetBoxNodeData(const in float i, inout vec4 boxNodeData0, inout vec4 boxNodeData1) | |
{ | |
// each bounding box's data is encoded in 2 rgba(or xyzw) texture slots | |
float ix2 = i * 2.0; | |
// (ix2 + 0.0) corresponds to .x = idTriangle, .y = aabbMin.x, .z = aabbMin.y, .w = aabbMin.z | |
// (ix2 + 1.0) corresponds to .x = idRightChild .y = aabbMax.x, .z = aabbMax.y, .w = aabbMax.z | |
ivec2 uv0 = ivec2(mod(ix2 + 0.0, 2048.0), (ix2 + 0.0) * INV_TEXTURE_WIDTH); // data0 | |
ivec2 uv1 = ivec2(mod(ix2 + 1.0, 2048.0), (ix2 + 1.0) * INV_TEXTURE_WIDTH); // data1 | |
boxNodeData0 = texelFetch(tAABBTexture, uv0, 0); | |
boxNodeData1 = texelFetch(tAABBTexture, uv1, 0); | |
} | |
vec3 randPointOnRectangle; | |
//---------------------------------------------------------------------------------------------------------------- | |
float RectangleIntersect( vec3 pos, vec3 normal, float radiusU, float radiusV, vec3 rayOrigin, vec3 rayDirection ) | |
//---------------------------------------------------------------------------------------------------------------- | |
{ | |
float dt = dot(-normal, rayDirection); | |
// use the following for one-sided rectangle | |
if (dt < 0.0) return INFINITY; | |
float t = dot(-normal, pos - rayOrigin) / dt; | |
if (t < 0.0) return INFINITY; | |
vec3 hit = rayOrigin + rayDirection * t; | |
vec3 vi = hit - pos; | |
vec3 U = normalize( cross( abs(normal.y) < 0.9 ? vec3(0, 1, 0) : vec3(0, 0, 1), normal ) ); | |
vec3 V = cross(normal, U); | |
return (abs(dot(U, vi)) > radiusU || abs(dot(V, vi)) > radiusV) ? INFINITY : t; | |
} | |
vec3 sampleRectangleLight(vec3 x, vec3 nl, Rectangle light, out float weight) | |
{ | |
// randPointOnRectangle has already been calculated in CalculateRadiance() function, | |
// so we can skip this next part | |
// vec3 U = normalize(cross( abs(light.normal.y) < 0.9 ? vec3(0, 1, 0) : vec3(0, 0, 1), light.normal)); | |
// vec3 V = cross(light.normal, U); | |
// vec3 randPointOnLight = light.position; | |
// randPointOnLight += U * light.radiusU * (rng() * 2.0 - 1.0) * 0.9; | |
// randPointOnLight += V * light.radiusV * (rng() * 2.0 - 1.0) * 0.9; | |
// randPointOnLight = vec3(m * vec4(randPointOnLight, 1.0)); | |
vec3 rotatedLightNormal; | |
if (light == rectangles[0]) | |
rotatedLightNormal = normalize(vec3( uLight0_Matrix * vec4(light.normal, 0.0) )); | |
else if (light == rectangles[1]) | |
rotatedLightNormal = normalize(vec3( uLight1_Matrix * vec4(light.normal, 0.0) )); | |
vec3 lightN = rotatedLightNormal;//dot(nl, rotatedLightNormal) < 0.0 ? rotatedLightNormal : -rotatedLightNormal; | |
vec3 dirToLight = randPointOnRectangle - x; | |
float r2 = (light.radiusU * 2.0) * (light.radiusV * 2.0); | |
float d2 = dot(dirToLight, dirToLight); | |
float cos_a_max = sqrt(1.0 - clamp( r2 / d2, 0.0, 1.0)); | |
dirToLight = normalize(dirToLight); | |
float dotNlRayDir = max(0.0, dot(nl, dirToLight)); | |
weight = 2.0 * (1.0 - cos_a_max) * max(0.0, -dot(dirToLight, lightN)) * dotNlRayDir; | |
weight = clamp(weight, 0.0, 1.0); | |
return dirToLight; | |
} | |
/* Credit: Some of the equi-angular sampling code is borrowed from https://www.shadertoy.com/view/Xdf3zB posted by user 'sjb' , | |
// who in turn got it from the paper 'Importance Sampling Techniques for Path Tracing in Participating Media' , | |
which can be viewed at: https://docs.google.com/viewer?url=https%3A%2F%2Fwww.solidangle.com%2Fresearch%2Fegsr2012_volume.pdf */ | |
void sampleEquiAngular(float u, float maxDistance, vec3 rOrigin, vec3 rDirection, vec3 lightPos, out float dist, out float pdf) | |
{ | |
// get coord of closest point to light along (infinite) ray | |
float delta = dot(lightPos - rOrigin, rDirection); | |
// get distance this point is from light | |
float D = distance(rOrigin + delta * rDirection, lightPos); | |
// get angle of endpoints | |
float thetaA = atan(0.0 - delta, D); | |
float thetaB = atan(maxDistance - delta, D); | |
// take sample | |
float t = D * tan(mix(thetaA, thetaB, u)); | |
dist = delta + t; | |
pdf = D / ((thetaB - thetaA) * (D * D + t * t)); | |
} | |
/* mat4 makeRotateX(float rot) | |
{ | |
float s = sin(rot); | |
float c = cos(rot); | |
return mat4( | |
1, 0, 0, 0, | |
0, c, s, 0, | |
0,-s, c, 0, | |
0, 0, 0, 1 | |
); | |
} | |
mat4 makeRotateY(float rot) | |
{ | |
float s = sin(rot); | |
float c = cos(rot); | |
return mat4( | |
c, 0,-s, 0, | |
0, 1, 0, 0, | |
s, 0, c, 0, | |
0, 0, 0, 1 | |
); | |
} | |
mat4 makeRotateZ(float rot) | |
{ | |
float s = sin(rot); | |
float c = cos(rot); | |
return mat4( | |
c, s, 0, 0, | |
-s, c, 0, 0, | |
0, 0, 1, 0, | |
0, 0, 0, 1 | |
); | |
} */ | |
//----------------------------------------------------------------------------------------------------------------------------------------------- | |
float SceneIntersect(vec3 rOrigin, vec3 rDirection, out vec3 hitNormal, out vec3 hitEmission, out vec3 hitColor, out float hitObjectID, out int hitType) | |
//----------------------------------------------------------------------------------------------------------------------------------------------- | |
{ | |
vec4 currentBoxNodeData0, nodeAData0, nodeBData0, tmpNodeData0; | |
vec4 currentBoxNodeData1, nodeAData1, nodeBData1, tmpNodeData1; | |
vec4 vd0, vd1, vd2, vd3, vd4, vd5, vd6, vd7; | |
vec3 inverseDir = 1.0 / rDirection; | |
vec3 rRotatedOrigin, rRotatedDirection; | |
vec2 currentStackData, stackDataA, stackDataB, tmpStackData; | |
ivec2 uv0, uv1, uv2, uv3, uv4, uv5, uv6, uv7; | |
float d; | |
float t = INFINITY; | |
float stackptr = 0.0; | |
float id = 0.0; | |
float tu, tv; | |
float triangleID = 0.0; | |
float triangleU = 0.0; | |
float triangleV = 0.0; | |
float triangleW = 0.0; | |
int objectCount = 0; | |
hitObjectID = -INFINITY; | |
bool skip = false; | |
bool triangleLookupNeeded = false; | |
hitIsModel = false; | |
// this part transforms the ray by the inverse of the matrix m (m holds the rectangle's transformations) | |
rRotatedOrigin = vec3( uLight0_InvMatrix * vec4(rOrigin, 1.0) ); | |
rRotatedDirection = vec3( uLight0_InvMatrix * vec4(rDirection, 0.0) ); | |
// NOTE: make sure to use rRotatedOrigin and rRotatedDirection (instead of the usual ray origin and direction) in the arguments to RectangleIntersect() below | |
d = RectangleIntersect( rectangles[0].position, rectangles[0].normal, rectangles[0].radiusU, rectangles[0].radiusV, rRotatedOrigin, rRotatedDirection ); // <---- | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = rectangles[0].normal; | |
hitNormal = vec3( transpose(uLight0_InvMatrix) * vec4(hitNormal, 0.0) ); | |
hitEmission = rectangles[0].emission; | |
hitColor = rectangles[0].color; | |
hitType = rectangles[0].type; | |
hitIsModel = false; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
rRotatedOrigin = vec3( uLight1_InvMatrix * vec4(rOrigin, 1.0) ); | |
rRotatedDirection = vec3( uLight1_InvMatrix * vec4(rDirection, 0.0) ); | |
// NOTE: make sure to use rRotatedOrigin and rRotatedDirection (instead of the usual ray origin and direction) in the arguments to RectangleIntersect() below | |
d = RectangleIntersect( rectangles[1].position, rectangles[1].normal, rectangles[1].radiusU, rectangles[1].radiusV, rRotatedOrigin, rRotatedDirection ); // <---- | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = rectangles[1].normal; | |
hitNormal = vec3( transpose(uLight1_InvMatrix) * vec4(hitNormal, 0.0) ); | |
hitEmission = rectangles[1].emission; | |
hitColor = rectangles[1].color; | |
hitType = rectangles[1].type; | |
hitIsModel = false; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
GetBoxNodeData(stackptr, currentBoxNodeData0, currentBoxNodeData1); | |
currentStackData = vec2(stackptr, BoundingBoxIntersect(currentBoxNodeData0.yzw, currentBoxNodeData1.yzw, rOrigin, inverseDir)); | |
stackLevels[0] = currentStackData; | |
skip = (currentStackData.y < t); | |
while (true) | |
{ | |
if (!skip) | |
{ | |
// decrease pointer by 1 (0.0 is root level, 27.0 is maximum depth) | |
if (--stackptr < 0.0) // went past the root level, terminate loop | |
break; | |
currentStackData = stackLevels[int(stackptr)]; | |
if (currentStackData.y >= t) | |
continue; | |
GetBoxNodeData(currentStackData.x, currentBoxNodeData0, currentBoxNodeData1); | |
} | |
skip = false; // reset skip | |
if (currentBoxNodeData0.x < 0.0) // < 0.0 signifies an inner node | |
{ | |
GetBoxNodeData(currentStackData.x + 1.0, nodeAData0, nodeAData1); | |
GetBoxNodeData(currentBoxNodeData1.x, nodeBData0, nodeBData1); | |
stackDataA = vec2(currentStackData.x + 1.0, BoundingBoxIntersect(nodeAData0.yzw, nodeAData1.yzw, rOrigin, inverseDir)); | |
stackDataB = vec2(currentBoxNodeData1.x, BoundingBoxIntersect(nodeBData0.yzw, nodeBData1.yzw, rOrigin, inverseDir)); | |
// first sort the branch node data so that 'a' is the smallest | |
if (stackDataB.y < stackDataA.y) | |
{ | |
tmpStackData = stackDataB; | |
stackDataB = stackDataA; | |
stackDataA = tmpStackData; | |
tmpNodeData0 = nodeBData0; | |
tmpNodeData1 = nodeBData1; | |
nodeBData0 = nodeAData0; | |
nodeBData1 = nodeAData1; | |
nodeAData0 = tmpNodeData0; | |
nodeAData1 = tmpNodeData1; | |
} // branch 'b' now has the larger rayT value of 'a' and 'b' | |
if (stackDataB.y < t) // see if branch 'b' (the larger rayT) needs to be processed | |
{ | |
currentStackData = stackDataB; | |
currentBoxNodeData0 = nodeBData0; | |
currentBoxNodeData1 = nodeBData1; | |
skip = true; // this will prevent the stackptr from decreasing by 1 | |
} | |
if (stackDataA.y < t) // see if branch 'a' (the smaller rayT) needs to be processed | |
{ | |
if (skip) // if larger branch 'b' needed to be processed also, | |
stackLevels[int(stackptr++)] = stackDataB; // cue larger branch 'b' for future round | |
// also, increase pointer by 1 | |
currentStackData = stackDataA; | |
currentBoxNodeData0 = nodeAData0; | |
currentBoxNodeData1 = nodeAData1; | |
skip = true; // this will prevent the stackptr from decreasing by 1 | |
} | |
continue; | |
} // end if (currentBoxNodeData0.x < 0.0) // inner node | |
// else this is a leaf | |
// each triangle's data is encoded in 8 rgba(or xyzw) texture slots | |
id = 8.0 * currentBoxNodeData0.x; | |
uv0 = ivec2(mod(id + 0.0, 2048.0), (id + 0.0) * INV_TEXTURE_WIDTH); | |
uv1 = ivec2(mod(id + 1.0, 2048.0), (id + 1.0) * INV_TEXTURE_WIDTH); | |
uv2 = ivec2(mod(id + 2.0, 2048.0), (id + 2.0) * INV_TEXTURE_WIDTH); | |
vd0 = texelFetch(tTriangleTexture, uv0, 0); | |
vd1 = texelFetch(tTriangleTexture, uv1, 0); | |
vd2 = texelFetch(tTriangleTexture, uv2, 0); | |
d = BVH_TriangleIntersect(vec3(vd0.xyz), vec3(vd0.w, vd1.xy), vec3(vd1.zw, vd2.x), rOrigin, rDirection, tu, tv); | |
if (d < t) | |
{ | |
t = d; | |
triangleID = id; | |
triangleU = tu; | |
triangleV = tv; | |
triangleLookupNeeded = true; | |
} | |
} // end while (true) | |
if (triangleLookupNeeded) | |
{ | |
//uv0 = ivec2( mod(triangleID + 0.0, 2048.0), (triangleID + 0.0) * INV_TEXTURE_WIDTH ); | |
//uv1 = ivec2( mod(triangleID + 1.0, 2048.0), (triangleID + 1.0) * INV_TEXTURE_WIDTH ); | |
uv2 = ivec2(mod(triangleID + 2.0, 2048.0), (triangleID + 2.0) * INV_TEXTURE_WIDTH); | |
uv3 = ivec2(mod(triangleID + 3.0, 2048.0), (triangleID + 3.0) * INV_TEXTURE_WIDTH); | |
uv4 = ivec2(mod(triangleID + 4.0, 2048.0), (triangleID + 4.0) * INV_TEXTURE_WIDTH); | |
uv5 = ivec2(mod(triangleID + 5.0, 2048.0), (triangleID + 5.0) * INV_TEXTURE_WIDTH); | |
//uv6 = ivec2( mod(triangleID + 6.0, 2048.0), (triangleID + 6.0) * INV_TEXTURE_WIDTH ); | |
//uv7 = ivec2( mod(triangleID + 7.0, 2048.0), (triangleID + 7.0) * INV_TEXTURE_WIDTH ); | |
//vd0 = texelFetch(tTriangleTexture, uv0, 0); | |
//vd1 = texelFetch(tTriangleTexture, uv1, 0); | |
vd2 = texelFetch(tTriangleTexture, uv2, 0); | |
vd3 = texelFetch(tTriangleTexture, uv3, 0); | |
vd4 = texelFetch(tTriangleTexture, uv4, 0); | |
vd5 = texelFetch(tTriangleTexture, uv5, 0); | |
//vd6 = texelFetch(tTriangleTexture, uv6, 0); | |
//vd7 = texelFetch(tTriangleTexture, uv7, 0); | |
// face normal for flat-shaded polygon look | |
//hitNormal = normalize( cross(vec3(vd0.w, vd1.xy) - vec3(vd0.xyz), vec3(vd1.zw, vd2.x) - vec3(vd0.xyz)) ); | |
// interpolated normal using triangle intersection's uv's | |
triangleW = 1.0 - triangleU - triangleV; | |
hitNormal = triangleW * vec3(vd2.yzw) + triangleU * vec3(vd3.xyz) + triangleV * vec3(vd3.w, vd4.xy); | |
hitEmission = vec3(0); | |
hitColor = vec3(1);//uMaterialColor;//vd6.yzw; | |
hitUV = triangleW * vec2(vd4.zw) + triangleU * vec2(vd5.xy) + triangleV * vec2(vd5.zw); | |
//hitType = int(uMaterialType);//int(vd6.x); | |
hitType = COAT; | |
//hitAlbedoTextureID = -1;//int(vd7.x); | |
hitIsModel = true; | |
hitObjectID = float(objectCount); | |
} | |
return t; | |
} // end float SceneIntersect( out bool finalIsRayExiting ) | |
//---------------------------------------------------------------------------------------------------------------------------------------------------- | |
vec3 CalculateRadiance(out vec3 objectNormal, out vec3 objectColor, out float objectID, out float pixelSharpness) | |
//---------------------------------------------------------------------------------------------------------------------------------------------------- | |
{ | |
Rectangle chosenRectangleLight; | |
vec3 cameraRayOrigin = rayOrigin; | |
vec3 cameraRayDirection = rayDirection; | |
vec3 vRayOrigin, vRayDirection; | |
// recorded intersection data (from eye): | |
vec3 eHitNormal, eHitEmission, eHitColor; | |
float eHitObjectID; | |
int eHitType = -100; // note: make sure to initialize this to a nonsense type id number! | |
// recorded intersection data (from volumetric particle): | |
vec3 vHitNormal, vHitEmission, vHitColor; | |
float vHitObjectID; | |
int vHitType = -100; // note: make sure to initialize this to a nonsense type id number! | |
vec3 accumCol = vec3(0); | |
vec3 mask = vec3(1); | |
// vec3 checkCol0 = vec3(1); | |
// vec3 checkCol1 = vec3(0.5); | |
vec3 lightVec; | |
vec3 particlePos; | |
vec3 tdir; | |
vec3 x, n, nl; | |
float t, vt, camt; | |
float u, xx; | |
float pdf; | |
float d; | |
float geomTerm; | |
float nc, nt, ratioIoR, Re, Tr; | |
float P, RP, TP; | |
float weight; | |
int diffuseCount = 0; | |
int previousIntersecType = -100; | |
// eHitType = -100; | |
bool coatTypeIntersected = false; | |
bool bounceIsSpecular = true; | |
bool sampleLight = false; | |
float trans; | |
vec3 lightPos; | |
vec3 dirToLight; | |
vec3 U0 = normalize(cross( abs(rectangles[0].normal.y) < 0.9 ? vec3(0, 1, 0) : vec3(0, 0, 1), rectangles[0].normal)); | |
vec3 V0 = cross(rectangles[0].normal, U0); | |
vec3 U1 = normalize(cross( abs(rectangles[1].normal.y) < 0.9 ? vec3(0, 1, 0) : vec3(0, 0, 1), rectangles[1].normal)); | |
vec3 V1 = cross(rectangles[1].normal, U1); | |
for (int bounces = 0; bounces < 5; bounces++) | |
{ | |
previousIntersecType = eHitType; | |
// reset random point | |
randPointOnRectangle = vec3(0); | |
u = rng(); | |
if (u < 0.5) | |
{ | |
randPointOnRectangle += U0 * rectangles[0].radiusU * (rng() * 2.0 - 1.0) * 0.9; | |
randPointOnRectangle += V0 * rectangles[0].radiusV * (rng() * 2.0 - 1.0) * 0.9; | |
randPointOnRectangle = vec3(uLight0_Matrix * vec4(randPointOnRectangle, 1.0)); | |
chosenRectangleLight = rectangles[0]; | |
} | |
else | |
{ | |
randPointOnRectangle += U1 * rectangles[1].radiusU * (rng() * 2.0 - 1.0) * 0.9; | |
randPointOnRectangle += V1 * rectangles[1].radiusV * (rng() * 2.0 - 1.0) * 0.9; | |
randPointOnRectangle = vec3(uLight1_Matrix * vec4(randPointOnRectangle, 1.0)); | |
chosenRectangleLight = rectangles[1]; | |
} | |
lightPos = randPointOnRectangle; | |
t = SceneIntersect(rayOrigin, rayDirection, eHitNormal, eHitEmission, eHitColor, eHitObjectID, eHitType); | |
// on first loop iteration, save intersection distance along camera ray (t) into camt variable for use below | |
if (bounces == 0) | |
{ | |
camt = t; | |
//objectNormal = eHitNormal; // handled below | |
objectColor = eHitColor; | |
objectID = eHitObjectID; | |
} | |
// if(bounces == 0) { | |
// objectNormal = nl; | |
// objectColor = eHitColor; | |
// objectID = eHitObjectID; | |
// } | |
// sample along intial ray from camera into the scene | |
sampleEquiAngular(u, camt, cameraRayOrigin, cameraRayDirection, lightPos, xx, pdf); | |
// create a particle along cameraRay and cast a shadow ray towards light (similar to Direct Lighting) | |
particlePos = cameraRayOrigin + xx * cameraRayDirection; | |
lightVec = lightPos - particlePos; | |
d = length(lightVec); | |
vRayOrigin = particlePos; | |
vRayDirection = normalize(lightVec); | |
vt = SceneIntersect(vRayOrigin, vRayDirection, vHitNormal, vHitEmission, vHitColor, vHitObjectID, vHitType); | |
// if the particle can see the light source, apply volumetric lighting calculation | |
if (vHitType == LIGHT) | |
{ | |
trans = exp( -((d + xx) * uFogDensity) ); | |
geomTerm = 1.0 / (d * d); | |
accumCol += vHitEmission * geomTerm * trans / pdf; | |
} | |
// otherwise the particle will remain in shadow - this is what produces the shafts of light vs. the volume shadows | |
// useful data | |
n = normalize(eHitNormal); | |
nl = dot(n, rayDirection) < 0.0 ? n : -n; | |
x = rayOrigin + rayDirection * t; | |
if (diffuseCount == 0) | |
{ | |
objectNormal = nl; | |
//objectColor = eHitColor; // handled above | |
//objectID = eHitObjectID; // handled above | |
} | |
if (eHitType == LIGHT) | |
{ | |
if (bounceIsSpecular || sampleLight) | |
{ | |
trans = exp(-((camt) * uFogDensity)); | |
accumCol += mask * eHitEmission * trans; | |
} | |
// reached a light, so we can exit | |
break; | |
} // end if (hitType == LIGHT) | |
// uncomment this tiny block of code if you wish the background to be simple black (or fog color fading to black) | |
// no HDRI will be shown in the background | |
if (t == INFINITY) | |
break; | |
if (bounces == 1 && diffuseCount == 0 && !coatTypeIntersected) | |
{ | |
objectNormal = nl; | |
} | |
// if we get here and sampleLight is still true, shadow ray failed to find a light source | |
if (sampleLight) | |
break; | |
if (eHitType == COAT) // Diffuse object underneath with ClearCoat on top (like car, or shiny pool ball) | |
{ | |
coatTypeIntersected = true; | |
nc = 1.0; // IOR of Air | |
nt = 1.5; // IOR of Clear Coat | |
Re = calcFresnelReflectance(rayDirection, nl, nc, nt, ratioIoR); | |
Tr = 1.0 - Re; | |
P = 0.25 + (0.5 * Re); | |
RP = Re / P; | |
TP = Tr / (1.0 - P); | |
if (diffuseCount == 0 && rand() < P) | |
{ | |
mask *= RP; | |
rayDirection = reflect(rayDirection, nl); // reflect ray from surface | |
rayOrigin = x + nl * uEPS_intersect; | |
continue; | |
} | |
diffuseCount++; | |
mask *= eHitColor; | |
mask *= TP; | |
bounceIsSpecular = false; | |
if (diffuseCount == 1 && rand() < 0.5) | |
{ | |
//mask *= 2.0; | |
// choose random Diffuse sample vector | |
rayDirection = randomCosWeightedDirectionInHemisphere(nl); | |
rayOrigin = x + nl * uEPS_intersect; | |
continue; | |
} | |
dirToLight = sampleRectangleLight(x, nl, chosenRectangleLight, weight); | |
// since we only selected 1 light source by random choice, but there are 2 light sources (much brighter total).. | |
// we must up-weight the contribution of the light that we did end up picking | |
//weight *= 2.0; // 2.0 = number of light source choices (rectangles[0] or rectangles[1]) | |
// the following line also upweights because there was 0.5 chance that we reflect off of clearCoat, or sample diffuse surface beneath the clearCoat | |
//mask *= diffuseCount == 1 ? 2.0 : 1.0; // multiply by number of choices: 2.0 (either specular reflection from ClearCoat surface layer, or diffuse reflection) | |
mask *= weight; | |
rayDirection = dirToLight; | |
rayOrigin = x + nl * uEPS_intersect; | |
sampleLight = true; | |
continue; | |
} //end if (hitType == COAT) | |
} // end for (int bounces = 0; bounces < 5; bounces++) | |
return max(vec3(0), accumCol); | |
} // end vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float objectID, out float pixelSharpness ) | |
//----------------------------------------------------------------------- | |
void SetupScene(void) | |
//----------------------------------------------------------------------- | |
{ | |
vec3 z = vec3(0); | |
vec3 L0 = vec3(1.0, 0.05, 1.0) * uLight0Power;// Bright Pinkish light | |
vec3 L1 = vec3(0.05, 0.05, 1.0) * uLight1Power;// Bright Blueish light | |
// NOTE: make sure to define this rectangle in object space, position = vec3(0) and its normal points in the +Z direction = vec3(0,0,1) | |
rectangles[0] = Rectangle(vec3(0), vec3(0,0,1), 2.0, 100.0, L0, z, LIGHT);// Pink Rectangle Area Light | |
rectangles[1] = Rectangle(vec3(0), vec3(0,0,1), 1.0, 50.0, L1, z, LIGHT);// Blue Rectangle Area Light | |
} | |
#include <pathtracing_main> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment