From 209662191b73e0118e3fad54e199a10085c739e9 Mon Sep 17 00:00:00 2001 From: Erich Loftis Date: Thu, 12 Sep 2024 14:34:04 -0500 Subject: [PATCH] Update GameEngine_PathTracer_Fragment.glsl --- shaders/GameEngine_PathTracer_Fragment.glsl | 144 +++++++++++--------- 1 file changed, 77 insertions(+), 67 deletions(-) diff --git a/shaders/GameEngine_PathTracer_Fragment.glsl b/shaders/GameEngine_PathTracer_Fragment.glsl index c386ad9f..a713e49f 100644 --- a/shaders/GameEngine_PathTracer_Fragment.glsl +++ b/shaders/GameEngine_PathTracer_Fragment.glsl @@ -28,7 +28,7 @@ vec3 rayOrigin, rayDirection; // recorded intersection data: vec3 hitNormal, hitEmission, hitColor; vec2 hitUV; -float hitObjectID; +float hitObjectID = -INFINITY; int hitType = -100; struct Sphere { float radius; vec3 position; vec3 emission; vec3 color; int type; }; @@ -86,6 +86,8 @@ float SceneIntersect(out int finalIsRayExiting) { vec3 rObjOrigin, rObjDirection; vec3 n; + vec3 hitPos; + float q; float d, dt; float t = INFINITY; int isRayExiting = FALSE; @@ -133,9 +135,11 @@ float SceneIntersect(out int finalIsRayExiting) if (d < t) { t = d; - hitNormal = (rayOrigin + rayDirection * t) - spheres[3].position; + hitPos = rayOrigin + (rayDirection * t); + hitNormal = hitPos - spheres[3].position; hitEmission = spheres[3].emission; - hitColor = spheres[3].color; + q = clamp( mod( dot( floor(hitPos.xz * 0.04), vec2(1.0) ), 2.0 ) , 0.0, 1.0 ); + hitColor = mix(vec3(0.5), spheres[3].color, q); hitType = spheres[3].type; hitObjectID = float(objectCount); } @@ -307,24 +311,25 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o vec3 checkCol0 = vec3(1); vec3 checkCol1 = vec3(0.5); vec3 dirToLight; - 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 previousObjectID; + int reflectionBounces = -1; int diffuseCount = 0; int previousIntersecType = -100; hitType = -100; - int coatTypeIntersected = FALSE; int bounceIsSpecular = TRUE; int sampleLight = FALSE; int isRayExiting; int willNeedReflectionRay = FALSE; + int isReflectionTime = FALSE; + int reflectionNeedsToBeSharp = FALSE; lightChoice = spheres[int(rand() * N_LIGHTS)]; @@ -332,17 +337,19 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o for (int bounces = 0; bounces < 8; bounces++) { + if (isReflectionTime == TRUE) + reflectionBounces++; + previousIntersecType = hitType; + previousObjectID = hitObjectID; t = SceneIntersect(isRayExiting); - /* - //not used in this scene because we are inside a huge sphere - no rays can escape + // shouldn't happen because we are inside a huge checkered sphere, but just in case if (t == INFINITY) { break; } - */ // useful data n = normalize(hitNormal); @@ -350,30 +357,36 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o x = rayOrigin + rayDirection * t; if (bounces == 0) + { + objectID = hitObjectID; + } + if (isReflectionTime == FALSE && diffuseCount == 0 && hitObjectID != previousObjectID) { objectNormal = nl; objectColor = hitColor; - objectID = hitObjectID; } - if (bounces == 1 && diffuseCount == 0 && previousIntersecType == SPEC) + if (reflectionNeedsToBeSharp == TRUE && reflectionBounces == 0) { objectNormal = nl; + objectColor = hitColor; } + if (hitType == LIGHT) { - if (bounces == 0 || (bounces == 1 && previousIntersecType == SPEC)) - pixelSharpness = 1.01; + if (diffuseCount == 0 && isReflectionTime == FALSE) + { + pixelSharpness = 1.01; // maximum sharpness for dynamic scenes + } - if (diffuseCount == 0) + if (isReflectionTime == TRUE && bounceIsSpecular == TRUE) { objectNormal = nl; - objectColor = hitColor; + //objectColor = hitColor; objectID = hitObjectID; } - if (bounceIsSpecular == TRUE || sampleLight == TRUE) accumCol += mask * hitEmission; @@ -386,7 +399,7 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o willNeedReflectionRay = FALSE; bounceIsSpecular = TRUE; sampleLight = FALSE; - diffuseCount = 0; + isReflectionTime = TRUE; continue; } // reached a light, so we can exit @@ -407,7 +420,7 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o willNeedReflectionRay = FALSE; bounceIsSpecular = TRUE; sampleLight = FALSE; - diffuseCount = 0; + isReflectionTime = TRUE; continue; } @@ -417,26 +430,17 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o - if (hitType == DIFF || hitType == CHECK) // Ideal DIFFUSE reflection + if (hitType == DIFF) // Ideal DIFFUSE reflection { - if( hitType == CHECK ) - { - float q = clamp( mod( dot( floor(x.xz * 0.04), vec2(1.0) ), 2.0 ) , 0.0, 1.0 ); - hitColor = checkCol0 * q + checkCol1 * (1.0 - q); - } - // must update objectColor because hitColor may have changed - if (bounces == 0 || (diffuseCount == 0 && coatTypeIntersected == FALSE && previousIntersecType == SPEC)) - objectColor = hitColor; - diffuseCount++; mask *= hitColor; bounceIsSpecular = FALSE; - if (diffuseCount == 1 && rand() < 0.4) + if (diffuseCount == 1 && rand() < 0.5) { - mask /= 0.4; + mask *= 2.0; // choose random Diffuse sample vector rayDirection = randomCosWeightedDirectionInHemisphere(nl); rayOrigin = x + nl * uEPS_intersect; @@ -444,7 +448,7 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o } dirToLight = sampleSphereLight(x, nl, lightChoice, weight); - mask /= diffuseCount == 1 ? 0.6 : 1.0; + mask *= diffuseCount == 1 ? 2.0 : 1.0; mask *= weight * N_LIGHTS; rayDirection = dirToLight; @@ -470,31 +474,26 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o if (hitType == REFR) // Ideal dielectric REFRACTION { - pixelSharpness = diffuseCount == 0 && coatTypeIntersected == FALSE ? -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; - if (bounces == 0 || (bounces == 1 && hitObjectID != objectID && bounceIsSpecular == TRUE)) + if (Re == 1.0) + { + rayDirection = reflect(rayDirection, nl); + rayOrigin = x + nl * uEPS_intersect; + continue; + } + + if (diffuseCount == 0 && hitObjectID != previousObjectID && n == nl) { reflectionMask = mask * Re; reflectionRayDirection = reflect(rayDirection, nl); // reflect ray from surface reflectionRayOrigin = x + nl * uEPS_intersect; willNeedReflectionRay = TRUE; - } - - if (Re == 1.0) - { - mask = reflectionMask; - rayOrigin = reflectionRayOrigin; - rayDirection = reflectionRayDirection; - - willNeedReflectionRay = FALSE; - bounceIsSpecular = TRUE; - sampleLight = FALSE; - continue; + if (bounces == 0 && hitColor == vec3(0.2,0.9,0.7) && isRayExiting == FALSE) + reflectionNeedsToBeSharp = TRUE; } // transmit ray through surface @@ -511,8 +510,7 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o mask *= Tr; - tdir = refract(rayDirection, nl, ratioIoR); - rayDirection = tdir; + rayDirection = refract(rayDirection, nl, ratioIoR); rayOrigin = x - nl * uEPS_intersect; // if (diffuseCount == 1) @@ -527,25 +525,24 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o if (hitType == COAT) // Diffuse object underneath with ClearCoat on top { - coatTypeIntersected = TRUE; - nc = 1.0; // IOR of Air nt = 1.4; // IOR of Clear Coat Re = calcFresnelReflectance(rayDirection, nl, nc, nt, ratioIoR); Tr = 1.0 - Re; - if (bounces == 0 || (bounces == 1 && hitObjectID != objectID && bounceIsSpecular == TRUE)) + if (diffuseCount == 0 && hitObjectID != previousObjectID) { reflectionMask = mask * Re; reflectionRayDirection = reflect(rayDirection, nl); // reflect ray from surface reflectionRayOrigin = x + nl * uEPS_intersect; willNeedReflectionRay = TRUE; + if (bounces == 0 && hitColor == vec3(0.04,0.04,0.04)) + reflectionNeedsToBeSharp = TRUE; } diffuseCount++; - if (bounces == 0) - mask *= Tr; + mask *= Tr; mask *= hitColor; bounceIsSpecular = FALSE; @@ -576,7 +573,7 @@ vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float o } //end if (hitType == COAT) - } // end for (int bounces = 0; bounces < 6; bounces++) + } // end for (int bounces = 0; bounces < 8; bounces++) return max(vec3(0), accumCol); @@ -598,7 +595,7 @@ void SetupScene(void) spheres[1] = Sphere(100.0, vec3( 300, 400,-300), L2, z, LIGHT);//spherical yellow Light2 spheres[2] = Sphere( 50.0, vec3( 500, 250,-100), L3, z, LIGHT);//spherical blue Light3 - spheres[3] = Sphere(1000.0, vec3( 0.0, 1000.0, 0.0), z, vec3(1.0, 1.0, 1.0), CHECK);//Checkered Floor + spheres[3] = Sphere(1000.0, vec3( 0.0, 1000.0, 0.0), z, vec3(1.0, 1.0, 1.0), DIFF);//Checkered Floor spheres[4] = Sphere( 16.5, vec3(-26.0, 17.2, 5.0), z, vec3(0.95, 0.95, 0.95), SPEC);//Mirror sphere spheres[5] = Sphere( 15.0, vec3( sin(mod(uTime * 0.3, TWO_PI)) * 80.0, 25, cos(mod(uTime * 0.1, TWO_PI)) * 80.0 ), z, vec3(1.0, 1.0, 1.0), REFR);//Glass sphere @@ -608,7 +605,7 @@ void SetupScene(void) openCylinders[0] = OpenCylinder( 15.0, 30.0, vec3( cos(mod(uTime * 0.1, TWO_PI)) * 100.0, 10, sin(mod(uTime * 0.4, TWO_PI)) * 100.0 ), z, vec3(0.9,0.01,0.01), REFR);//red glass open Cylinder - cappedCylinders[0] = CappedCylinder( 14.0, vec3(-60,0,20), vec3(-60,14,20), z, vec3(0.05,0.05,0.05), COAT);//dark gray capped Cylinder + cappedCylinders[0] = CappedCylinder( 14.0, vec3(-60,0,20), vec3(-60,14,20), z, vec3(0.04,0.04,0.04), COAT);//dark gray capped Cylinder cones[0] = Cone( vec3(1,20,-12), 15.0, vec3(1,0,-12), 0.0, z, vec3(0.01,0.1,0.5), REFR);//blue Cone @@ -645,8 +642,9 @@ void main( void ) randNumber = 0.0; // the final randomly-generated number (range: 0.0 to 1.0) blueNoise = texelFetch(tBlueNoiseTexture, ivec2(mod(floor(gl_FragCoord.xy), 128.0)), 0).r; - vec2 pixelOffset = vec2( tentFilter(rand()), tentFilter(rand()) ) * 0.5; - + vec2 pixelOffset = vec2( tentFilter(rand()), tentFilter(rand()) ); + pixelOffset *= 0.5;//uCameraIsMoving ? 0.5 : 0.75; + // we must map pixelPos into the range -1.0 to +1.0 vec2 pixelPos = ((gl_FragCoord.xy + vec2(0.5) + pixelOffset) / uResolution) * 2.0 - 1.0; @@ -721,20 +719,32 @@ void main( void ) currentPixel.rgb *= 0.5; } - - if (colorDifference >= 1.0 || normalDifference >= 1.0 || objectDifference >= 1.0) - pixelSharpness = 1.01; - currentPixel.a = pixelSharpness; - // makes sharp edges more stable + // check for all edges that are not light sources + if (pixelSharpness < 1.01 && (colorDifference >= 1.0 || normalDifference >= 1.0 || objectDifference >= 1.0)) // all other edges + currentPixel.a = pixelSharpness = 1.0; + + // makes light source edges (shape boundaries) more stable if (previousPixel.a == 1.01) - currentPixel.a = 1.01; + { + if (pixelSharpness > 0.0) + currentPixel.a = 1.01; + else currentPixel.a = 1.0; + } + // makes sharp edges more stable + if (!uCameraIsMoving && previousPixel.a == 1.0) + { + if (pixelSharpness > 0.0) + currentPixel.a = 1.01; + else currentPixel.a = 1.0; + } + // for dynamic scenes (to clear out old, dark, sharp pixel trails left behind from moving objects) - if (previousPixel.a == 1.01 && rng() < 0.05) - currentPixel.a = 1.0; - + if (previousPixel.a == 1.0 && rng() < 0.05) + currentPixel.a = 0.0; + pc_fragColor = vec4(previousPixel.rgb + currentPixel.rgb, currentPixel.a); }