Created
April 2, 2022 06:03
-
-
Save erichlof/67a9e2c44eec234d7dd2b2c8257cc454 to your computer and use it in GitHub Desktop.
Handling multiple light sources (HDRI, Quad light, Sphere light)
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; | |
uniform sampler2D tHDRTexture; | |
#include <pathtracing_uniforms_and_defines> | |
uniform vec3 uMaterialColor; | |
uniform vec3 uHDRIColor; | |
uniform vec3 uSunDirectionVector; | |
uniform float uHDRI_Exposure; | |
uniform int uUSE_HDRI; | |
uniform float uRoughness; | |
uniform int uMaterialType; | |
//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 | |
// the following directions pointing at the sun were found by trial and error: left here just for reference | |
//#define SUN_DIRECTION normalize(vec3(-0.555, 1.0, 0.205)) // use this vec3 for the symmetrical_garden_2k.hdr environment | |
//#define SUN_DIRECTION normalize(vec3(0.54, 1.0, -0.595)) // use this vec3 for the kiara_5_noon_2k.hdr environment | |
#define N_SPHERES 1 | |
#define N_QUADS 1 | |
// #define N_BOXES 2 | |
//----------------------------------------------------------------------- | |
vec3 rayOrigin, rayDirection; | |
// recorded intersection data: | |
vec3 hitNormal, hitEmission, hitColor; | |
vec2 hitUV; | |
int hitType; | |
float hitObjectID; | |
bool hitIsModel; | |
struct Quad { vec3 normal; vec3 v0; vec3 v1; vec3 v2; vec3 v3; 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; }; | |
Sphere spheres[N_SPHERES]; | |
Quad quads[N_QUADS]; | |
// Box boxes[N_BOXES]; | |
#include <pathtracing_random_functions> | |
#include <pathtracing_calc_fresnel_reflectance> | |
#include <pathtracing_sphere_intersect> | |
// #include <pathtracing_box_intersect> | |
#include <pathtracing_boundingbox_intersect> | |
#include <pathtracing_bvhTriangle_intersect> | |
#include <pathtracing_quad_intersect> | |
//#include <pathtracing_bvhDoubleSidedTriangle_intersect> | |
#include <pathtracing_sample_sphere_light> | |
#include <pathtracing_sample_quad_light> | |
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); | |
} | |
//----------------------------------------------------------------------------------------------------------------------------------------------- | |
float SceneIntersect( out bool finalIsRayExiting ) | |
//----------------------------------------------------------------------------------------------------------------------------------------------- | |
{ | |
vec4 currentBoxNodeData0, nodeAData0, nodeBData0, tmpNodeData0; | |
vec4 currentBoxNodeData1, nodeAData1, nodeBData1, tmpNodeData1; | |
vec4 vd0, vd1, vd2, vd3, vd4, vd5, vd6, vd7; | |
vec3 inverseDir = 1.0 / rayDirection; | |
vec3 normal; | |
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; | |
bool isRayExiting = false; | |
hitIsModel = false; | |
for (int i = 0; i < N_SPHERES; i++) | |
{ | |
d = SphereIntersect( spheres[i].radius, spheres[i].position, rayOrigin, rayDirection ); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = (rayOrigin + rayDirection * t) - spheres[i].position; | |
hitEmission = spheres[i].emission; | |
hitColor = spheres[i].color; | |
hitType = spheres[i].type; | |
hitIsModel = false; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
} | |
for (int i = 0; i < N_QUADS; i++) | |
{ | |
d = QuadIntersect( quads[i].v0, quads[i].v1, quads[i].v2, quads[i].v3, rayOrigin, rayDirection, false ); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = quads[i].normal; | |
hitEmission = quads[i].emission; | |
hitColor = quads[i].color; | |
hitType = quads[i].type; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
} | |
// for (int i = 0; i < N_BOXES; i++) | |
// { | |
// d = BoxIntersect( boxes[i].minCorner, boxes[i].maxCorner, rayOrigin, rayDirection, normal, isRayExiting ); | |
// if (d < t) | |
// { | |
// t = d; | |
// hitNormal = normal; | |
// hitEmission = boxes[i].emission; | |
// hitColor = boxes[i].color; | |
// hitType = boxes[i].type; | |
// hitIsModel = false; | |
// finalIsRayExiting = isRayExiting; | |
// hitObjectID = float(objectCount); | |
// } | |
// objectCount++; | |
// } | |
GetBoxNodeData(stackptr, currentBoxNodeData0, currentBoxNodeData1); | |
currentStackData = vec2(stackptr, BoundingBoxIntersect(currentBoxNodeData0.yzw, currentBoxNodeData1.yzw, rayOrigin, 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, rayOrigin, inverseDir)); | |
stackDataB = vec2(currentBoxNodeData1.x, BoundingBoxIntersect(nodeBData0.yzw, nodeBData1.yzw, rayOrigin, 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), rayOrigin, rayDirection, 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 = uMaterialColor;//vd6.yzw; | |
hitUV = triangleW * vec2(vd4.zw) + triangleU * vec2(vd5.xy) + triangleV * vec2(vd5.zw); | |
hitType = int(uMaterialType);//int(vd6.x); | |
//hitAlbedoTextureID = -1;//int(vd7.x); | |
hitIsModel = true; | |
hitObjectID = float(objectCount); | |
} | |
return t; | |
} // end float SceneIntersect( out bool finalIsRayExiting ) | |
vec3 Get_HDR_Color(vec3 rDirection) | |
{ | |
vec2 sampleUV; | |
//sampleUV.y = asin(clamp(rDirection.y, -1.0, 1.0)) * ONE_OVER_PI + 0.5; | |
///sampleUV.x = (1.0 + atan(rDirection.x, -rDirection.z) * ONE_OVER_PI) * 0.5; | |
sampleUV.x = atan(rDirection.x, -rDirection.z) * ONE_OVER_TWO_PI + 0.5; | |
sampleUV.y = acos(rDirection.y) * ONE_OVER_PI; | |
vec3 texColor = texture(tHDRTexture, sampleUV).rgb; | |
// texColor = texData.a > 0.57 ? vec3(100) : vec3(0); | |
// return texColor; | |
return texColor * uHDRI_Exposure; | |
} | |
//---------------------------------------------------------------------------------------------------------------------------------------------------- | |
vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float objectID, out float pixelSharpness ) | |
//---------------------------------------------------------------------------------------------------------------------------------------------------- | |
{ | |
vec3 accumCol = vec3(0); | |
vec3 mask = vec3(1); | |
vec3 checkCol0 = vec3(1); | |
vec3 checkCol1 = vec3(0.5); | |
vec3 tdir; | |
vec3 x, n, nl; | |
float t; | |
float nc, nt, ratioIoR, Re, Tr; | |
float P, RP, TP; | |
float weight; | |
float thickness = 0.1; | |
float roughness = 0.0; | |
float randomLightChoice = 0.0; | |
int diffuseCount = 0; | |
int previousIntersecType = -100; | |
hitType = -100; | |
bool coatTypeIntersected = false; | |
bool bounceIsSpecular = true; | |
bool sampleLight = false; | |
bool isRayExiting = false; | |
vec3 dirToLight; | |
//vec3 dirToLight2; | |
for (int bounces = 0; bounces < 5; bounces++) | |
{ | |
previousIntersecType = hitType; | |
t = SceneIntersect(isRayExiting); | |
roughness = hitIsModel ? uRoughness : roughness; | |
if (hitType == LIGHT) | |
{ | |
if (bounceIsSpecular || sampleLight) | |
accumCol = mask * hitEmission; | |
// reached a light, so we can exit | |
break; | |
} // end if (hitType == LIGHT) | |
if (t == INFINITY) | |
{ | |
vec3 environmentCol = Get_HDR_Color(rayDirection); | |
// looking directly at sky | |
if (bounces == 0) | |
{ | |
pixelSharpness = 1.01; | |
// if (uUSE_HDRI == 0) | |
// { | |
// // accumCol = vec3(0.001,0.001,0.001); | |
// accumCol = uHDRIColor; | |
// } | |
// else | |
// { | |
// accumCol = environmentCol; | |
// } | |
accumCol = environmentCol; | |
break; | |
} | |
// sun light source location in HDRI image is sampled by a diffuse surface | |
// mask has already been down-weighted in this case | |
if (sampleLight) | |
{ | |
accumCol = mask * environmentCol; | |
break; | |
} | |
// sky image seen in a reflection or refraction | |
// if (bounceIsSpecular) | |
// { | |
// // try to get rid of fireflies on rougher surfaces | |
// if (dot(rayDirection, uSunDirectionVector) > 0.98) | |
// environmentCol = vec3(1); | |
// //environmentCol = mix( vec3(1), environmentCol, clamp(pow(roughness, 0.0), 0.0, 1.0) ); | |
// accumCol = mask * environmentCol; | |
// break; | |
// } | |
// random diffuse bounce hits sky | |
if ( !bounceIsSpecular ) | |
{ | |
weight = dot(rayDirection, uSunDirectionVector) < 0.98 ? 1.0 : 0.0; | |
accumCol = mask * environmentCol * weight; | |
// note: you don't need this line because the glass table and checker floor (huge sphere below) both are not in your scene setup | |
//if (bounces == 3) accumCol = mask * environmentCol * weight * 2.0; // checkered ground beneath glass table | |
break; | |
} | |
if (bounceIsSpecular) | |
{ | |
if (coatTypeIntersected) | |
{ | |
if (dot(rayDirection, uSunDirectionVector) > 0.998) | |
pixelSharpness = 1.01; | |
} | |
else | |
pixelSharpness = 1.01; | |
if (dot(rayDirection, uSunDirectionVector) > 0.8) | |
{ | |
environmentCol = mix(vec3(1), environmentCol, clamp(pow(1.0-roughness, 20.0), 0.0, 1.0)); | |
} | |
accumCol = mask * environmentCol; | |
break; | |
} | |
// reached the HDRI sky light, so we can exit | |
break; | |
} // end if (t == INFINITY) | |
// useful data | |
n = normalize(hitNormal); | |
nl = dot(n, rayDirection) < 0.0 ? n : -n; | |
x = rayOrigin + rayDirection * t; | |
if (bounces == 0) | |
{ | |
objectNormal = nl; | |
objectColor = hitColor; | |
objectID = hitObjectID; | |
} | |
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 (hitType == SPEC) // Ideal SPECULAR reflection | |
{ | |
mask *= hitColor; | |
rayDirection = randomDirectionInSpecularLobe(reflect(rayDirection, nl), roughness); | |
rayOrigin = x + nl * uEPS_intersect; | |
continue; | |
} | |
if (hitType == REFR) // Ideal dielectric REFRACTION | |
{ | |
pixelSharpness = diffuseCount == 0 ? -1.0 : pixelSharpness; | |
nc = 1.0; // IOR of Air | |
nt = 1.5; // IOR of common Glass | |
Re = calcFresnelReflectance(rayDirection, n, 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 = randomDirectionInSpecularLobe(reflect(rayDirection, nl), roughness); | |
rayOrigin = x + nl * uEPS_intersect; | |
continue; | |
} | |
// transmit ray through surface | |
mask *= TP; | |
// is ray leaving a solid object from the inside? | |
// If so, attenuate ray color with object color by how far ray has travelled through the medium | |
if (isRayExiting || (distance(n, nl) > 0.1)) | |
{ | |
isRayExiting = false; | |
mask *= exp(log(hitColor) * thickness * t); | |
} | |
else | |
mask *= hitColor; | |
tdir = refract(rayDirection, nl, ratioIoR); | |
rayDirection = randomDirectionInSpecularLobe(tdir, roughness * roughness); | |
rayOrigin = x - nl * uEPS_intersect; | |
continue; | |
} // end if (hitType == REFR) | |
if (hitType == 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 = randomDirectionInSpecularLobe(reflect(rayDirection, nl), roughness); | |
rayOrigin = x + nl * uEPS_intersect; | |
continue; | |
} | |
diffuseCount++; | |
mask *= hitColor; | |
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; | |
} | |
randomLightChoice = rng(); // will be in the range 0.0-1.0 | |
// in Monte Carlo path tracing, we can only select 1 possible 'dirToLight' path by random choice | |
// in other words, we can... | |
// either sample the Sun | |
if (randomLightChoice < 0.33) | |
{ | |
dirToLight = randomDirectionInSpecularLobe(uSunDirectionVector, 0.03); | |
weight = max(0.0, dot(dirToLight, nl)) * 0.000015; // down-weight directSunLight contribution | |
} | |
// or sample the large quad area light over the model | |
else if (randomLightChoice < 0.66) | |
{ | |
dirToLight = sampleQuadLight(x, nl, quads[0], weight); | |
} | |
// or sample the small sphere area light | |
else if (randomLightChoice < 1.0) | |
{ | |
dirToLight = sampleSphereLight(x, nl, spheres[0], weight); | |
} | |
// since we only selected 1 light source by random choice, but there are 3 light sources (much brighter).. | |
// we must up-weight the contribution of the light that we did end up picking | |
weight *= 3.0; // 3.0 = number of light source choices (Sun, Quad, Sphere) | |
// 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 spec reflection, or diffuse) | |
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 L1 = vec3(5.0, 1.0, 1.0) * 25.0;// Bright Yellow light | |
vec3 L2 = vec3(6.0, 1.0, 0.0) * 1.0;// Yellow light | |
// spheres[0] = Sphere( 4000.0, vec3(0, -4000, 0), z, vec3(0.4,0.4,0.4), CHECK);//Checkered Floor | |
// spheres[1] = Sphere( 6.0, vec3(55, 36, -45), z, vec3(0.9), SPEC);//small mirror ball | |
// spheres[2] = Sphere( 6.0, vec3(55, 24, -45), z, vec3(0.5,1.0,1.0), REFR);//small glass ball | |
// spheres[3] = Sphere( 6.0, vec3(60, 24, -30), z, vec3(1.0), COAT);//small plastic ball | |
// spheres[0] = Sphere(150.0, vec3(-400, 900, 200), L1, z, 0.0, SPEC);//spherical white Light1 | |
spheres[0] = Sphere( 3.2, vec3(0, 36, -45), L1, z, LIGHT);//small sphere light | |
quads[0] = Quad( vec3(0,-1, 0), vec3(-10, 40,-32), vec3(3, 40,-32), vec3(3, 40,-27), vec3(-10, 40,-27), L2, z, LIGHT);// Area Light Rectangle above model | |
// boxes[0] = Box( vec3(-20.0,11.0,-110.0), vec3(70.0,18.0,-20.0), z, vec3(0.2,0.9,0.7), REFR);//Glass Box | |
// boxes[1] = Box( vec3(-14.0,13.0,-104.0), vec3(64.0,16.0,-26.0), z, vec3(0), DIFF);//Inner Box | |
} | |
#include <pathtracing_main> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment