problem with refractions in glsl (raymarching)

43 Views Asked by At

I'm currently working on implementing dielectric materials in my raymarching renderer. Despite several attempts and thorough consideration of total internal reflection, I'm facing a peculiar problem. Strangely, the issue arises specifically when rendering a box, whereas everything works as expected when rendering a sphere. It appears that total internal reflection is not occurring inside the sphere, but I'm uncertain about what might be causing this behavior. I've double-checked my implementation for handling total internal reflection, yet the problem persists. Any insights or suggestions on what might be causing this discrepancy would be greatly appreciated.

the code:

raymarching function: ("side" can be +1.0 or -1.0 which indicate if we march inside or outside a object)

MapValue raymarching(vec3 p, vec3 rd, float side)
{
    float th = epsilon;
    float d0 = 0.0;
    int mat = 0;

    objectsNearRay(p.xyz, rd.xyz, MAX_DST);

    for (int i = 0; i < MAX_ITR; i++)
    {
        MapValue mv = map(p);
        float d = side*mv.dist;
        d0 += d;
        p += d*rd;
        mat = mv.mat;

        if (d < th || d0 > MAX_DST) {break;}
        th = epsilon*d0*0.1;
    }
    return MapValue(d0, mat);
}

calcNormal function:


vec3 calcNormal(vec3 p)
{
    const vec2 e = vec2(0.001, 0.0);
    const float vp = map(p).dist;
    const vec3 n = vec3(vp - map(p - e.xyy).dist,
                    vp - map(p - e.yxy).dist,
                    vp - map(p - e.yyx).dist);
    return normalize(n);
}

render function (returns a color for a given pixel to draw on screen):

        vec3 ro = _ro;
        vec3 rd = getRd(uv);

        MapValue mv = raymarching(ro, rd, 1.0);

        Material mat = materials[mv.mat];
        vec3 p = ro + rd*mv.dist;
        vec3 normal = calcNormal(p);

        if (mv.dist >= MAX_DST)
        {
            return calcSky(rd);
        }

        if (mat.refract == 1)
        {
           float IOR = mix(mat.IOR, 1.0/mat.IOR, float(mat.IOR < 1.0));

           vec3 p_enter = p - normal*epsilon*3.0;
           vec3 rd_enter = refract(rd, normal, 1.0/IOR);
           MapValue mv_enter = raymarching(p_enter, rd_enter, -1.0);

           vec3 p_edge_exit = p_enter + rd_enter*mv_enter.dist;
           vec3 normal_exit = -calcNormal(p_edge_exit);
           vec3 p_exit = p_edge_exit - normal_exit*3.0*epsilon;
           vec3 rd_exit = refract(rd_enter, normal_exit, mat.IOR);

           // total internal reflection
           if (dot(rd_exit, rd_exit) == 0.0) {rd_exit = reflect(rd_enter, normal_exit);}


           MapValue mv_exit = raymarching(p_exit, rd_exit, 1.0);


           if (mv_exit.dist >= MAX_DST)
           {
               return calcSky(rd_exit);
           }
           vec3 p_outside = p_exit + rd_exit*mv_exit.dist;
           Material m = materials[mv_exit.mat];
           vec3 refracted_color = calcLight(p_outside, rd_exit, calcNormal(p_outside), m);
           return refracted_color;
        }

i tried debugging by returning rd_enter, rd_exit, and normal_exit didn't notice a problem with those.

it seems that the ray is marching in the direction of the cube itself and in some cases return its color

result with a box result with a sphere

(magenta is the albedo of the material which should not be visible)

0

There are 0 best solutions below