Light Transport Artifacts with Signed Distance Functions

35 Views Asked by At

I've been messing around with ray-marched geometry for a game engine and recently messed around with a fully ray-driven lighting system. At one stage I had a very nice system that accurately traced rays back to their source and created a moon-like directly illuminated sphere, but I overwrote that code with a "better" ray-marched version (original was ray-traced) that wasn't and now I'm seeing alternating discs of shadowed and unshadowed surfaces. I know from the tutorial here that my lighting algorithm is borked, but I'd still be interested to know how.

Here's my lighting code (float3s are vectors):

float3 lightPos = float3(5.0f, 0.0f, 0.0f);
float3 rayDir = normalize(lightPos - samplePoint);
float currRayDist = 0.00001f;
float3 outputColor = sampleRGB;

for (int i = 0; i < MAX_MARCHER_STEPS; i += 1)
{
    float3 reflectVec = samplePoint + (rayDir * currRayDist);
    float distToScene = SceneSDF(reflectVec);
    float invSquare = (10 / (4 * 3.14159 * (currRayDist * currRayDist)));
    if (distToScene < rayEpsilon)
    {
        // We hit geometry, so this point must be in shadow;
        // darken it appropriately
        outputColor = sampleRGB * (1 / invSquare);
        break;
    }

    float distToLight = SphereSDF((rayDir * currRayDist), 2.0f, lightPos);
    if (distToLight < rayEpsilon)
    {
        // The ray successfully made it's way back to the light source, so use the
        // inverse square law to update the output color :)
        outputColor = sampleRGB * invSquare;
        break;
    }

    currRayDist += distToLight;
}

And here's a low-res image of the artifacts:

Mystery discs, 10 rays