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)