Skip to content

Commit

Permalink
gi: protections against division by zero
Browse files Browse the repository at this point in the history
  • Loading branch information
pablode committed May 26, 2024
1 parent 9f0004a commit 3a2c098
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 10 deletions.
21 changes: 20 additions & 1 deletion src/gi/shaders/common.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ const float PI = 3.1415926535897932384626433832795;
#define AOV_ID_DEBUG_SIDEDNESS 10
#define AOV_ID_OBJECTID 11

float safe_div(float f1, float f2)
{
return (f2 == 0.0) ? 0.0 : (f1 / f2);
}

vec3 safe_div(vec3 v, float f)
{
return (f == 0.0) ? vec3(0.0) : (v / f);
}

vec3 safe_div(vec3 v1, vec3 v2)
{
return vec3(
(v2.x == 0.0) ? 0.0 : (v1.x / v2.x),
(v2.y == 0.0) ? 0.0 : (v1.y / v2.y),
(v2.z == 0.0) ? 0.0 : (v1.z / v2.z)
);
}

vec4 uvec4AsVec4(uvec4 v)
{
v >>= 9;
Expand Down Expand Up @@ -238,7 +257,7 @@ vec2 sample_disk(vec2 xi, vec2 radius)
else
{
r = radius * b;
phi = (PI / 2) - (PI / 4) * (a / b);
phi = (PI / 2) - (PI / 4) * safe_div(a, b);
}

return r * vec2(cos(phi), sin(phi));
Expand Down
12 changes: 6 additions & 6 deletions src/gi/shaders/rp_main.chit
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ void sampleLight(vec4 k4, vec3 surfacePos, out vec3 dirToLight, out float dist,
vec3 samplePos = light.pos + sample_sphere(k4.zw, light.radiusXYZ);
vec3 dir = samplePos - surfacePos;
dist = length(dir);
dirToLight = dir / dist;
dirToLight = safe_div(dir, dist);

// https://graphics.cg.uni-saarland.de/courses/ris-2021/slides/03_ProbabilityTheory_MonteCarlo.pdf s.35
vec3 lightNormal = normalize(samplePos - light.pos);
float cosTheta = max(0.0, dot(-dirToLight, lightNormal));
invPdf = ((light.area > 0.0) ? (light.area * cosTheta) : 1.0) / (dist * dist);
invPdf = safe_div((light.area > 0.0) ? (light.area * cosTheta) : 1.0, dist * dist);

power = light.baseEmission * PC.lightIntensityMultiplier;
diffuseSpecularPacked = light.diffuseSpecularPacked;
Expand Down Expand Up @@ -88,12 +88,12 @@ void sampleLight(vec4 k4, vec3 surfacePos, out vec3 dirToLight, out float dist,

vec3 dir = samplePos - surfacePos;
dist = length(dir);
dirToLight = dir / dist;
dirToLight = safe_div(dir, dist);

vec3 lightNormal = cross(t1, t0); // light forward/default dir is -Z (like UsdLux)
float cosTheta = max(0.0, dot(-dirToLight, lightNormal));
float area = light.width * light.height;
invPdf = ((area > 0.0) ? (area * cosTheta) : 1.0) / (dist * dist);
invPdf = safe_div((area > 0.0) ? (area * cosTheta) : 1.0, dist * dist);

power = light.baseEmission * PC.lightIntensityMultiplier;
diffuseSpecularPacked = light.diffuseSpecularPacked;
Expand All @@ -115,12 +115,12 @@ void sampleLight(vec4 k4, vec3 surfacePos, out vec3 dirToLight, out float dist,

vec3 dir = samplePos - surfacePos;
dist = length(dir);
dirToLight = dir / dist;
dirToLight = safe_div(dir, dist);

vec3 lightNormal = cross(t1, t0); // light forward/default dir is -Z (like UsdLux)
float cosTheta = max(0.0, dot(-dirToLight, lightNormal));
float area = radiusXY.x * radiusXY.y * PI;
invPdf = ((area > 0.0) ? (area * cosTheta) : 1.0) / (dist * dist);
invPdf = safe_div((area > 0.0) ? (area * cosTheta) : 1.0, dist * dist);

power = light.baseEmission * PC.lightIntensityMultiplier;
diffuseSpecularPacked = light.diffuseSpecularPacked;
Expand Down
6 changes: 3 additions & 3 deletions src/gi/shaders/rp_main.rgen
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ vec3 evaluate_sample(vec3 ray_origin,

// Correct clip plane curving by getting the hypothenuse length (our current ray)
// from the adjacent edge (the forward vector) the angle between both.
float cosConeAngle = dot(ray_dir, PC.cameraForward);
float cosConeAngle = max(1e-5, dot(ray_dir, PC.cameraForward));
vec2 clipRange = unpackHalf2x16(PC.clipRangePacked) / cosConeAngle;

// Path trace
Expand Down Expand Up @@ -128,10 +128,10 @@ vec3 evaluate_sample(vec3 ray_origin,

vec3 shadowRayOrigin = rayPayload.ray_origin; // actually not correct, but we compensate with tMin
float lightDist = length(rayPayload.neeToLight);
vec3 shadowRayDir = rayPayload.neeToLight / lightDist;
vec3 shadowRayDir = safe_div(rayPayload.neeToLight, lightDist); // according to spec, must not contain NaNs

// NV best practices recommends unconditional dispatch with tMin = tMax = 0.0
bool traceRay = luminance(rayPayload.neeContrib) > 1e-6 && lightDist > 0.0;
bool traceRay = luminance(rayPayload.neeContrib) > 1e-6 && lightDist > 1e-9;
uint rayFlags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT;
float tMin = traceRay ? 0.01 : 0.0; // FIXME: investigate resulting artifacts
float tMax = traceRay ? lightDist : 0.0;
Expand Down

0 comments on commit 3a2c098

Please sign in to comment.