# Ray-Marching: Rendering a Voxel Grid with Proper Normals

Dear Computer Graphics SE,

I have a RAYMARCHING renderer, that looks up voxel data from a 3D texture. Each cell in the texture can be 0 or 1.

I have a very simple algorithm for calculating the signed distance at a given point p in space. Here is some pseudocode

Let p be some vec3(x,y,z)
Let v = value of the 3D texture at point p (0 or 1)
If v == 1:
sdf=0.0
If v == 0:
sdf = cell_width/2.0


This works fine to find the intersection point between the ray and the voxel grid for raymarching, but this totally messes with the normals. More specifically, normals in +x, +y, +z direction work fine, but normals that should be in the -x, -y, -z directions show up as vec3(0.0) instead.

Here is my normal algorithm (glsl):

vec3 get_normal(vec3 intersection){

vec3 axis1 = intersection+vec3(1.0,0.0,0.0)*normal_epsilon;
vec3 axis2 = intersection+vec3(0.0,1.0,0.0)*normal_epsilon;
vec3 axis3 = intersection+vec3(0.0,0.0,1.0)*normal_epsilon;

float d1 = primary_sdf(axis1);
float d2 = primary_sdf(axis2);
float d3 = primary_sdf(axis3);

vec3 n = normalize(vec3(d1,d2,d3));

return n;

}


What is the best way to get a good sdf for my voxel field, that won't break the normals?

To estimate the normal at a point, you need to find the gradient of the distance field in the immediate vicinity of the point. You need the rate of change, not the actual values.

vec3 getNormal(vec3 p) {
return normalize(vec3(
getSDF(vec3(p.x + EPSILON, p.y, p.z)) - getSDF(vec3(p.x - EPSILON, p.y, p.z)),
getSDF(vec3(p.x, p.y + EPSILON, p.z)) - getSDF(vec3(p.x, p.y - EPSILON, p.z)),
getSDF(vec3(p.x, p.y, p.z + EPSILON)) - getSDF(vec3(p.x, p.y, p.z - EPSILON))
));
}


However, a set of 1 and 0 values is not a proper signed distance field, so it's not clear if this will work.

• I tested something similar to your solution, but it doesn't really work. I have since solved the problem another way, by constructing a normal via testing neighboring cells. Perhaps I should unlist this question. Sep 7, 2021 at 14:31
• @MichaelSohnen you can not, it has an answer. But why don't you write your own answer? Sep 8, 2021 at 6:13