<p>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.</p>
<pre><code>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))
   ));
}
</code></pre>
<p>However, a set of 1 and 0 values is not a proper signed distance field, so it's not clear if this will work.</p>

CC BY-SA 4.0
2021-09-07T14:31:32.107Z
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.
Michael Sohnen
CC BY-SA 4.0
2021-09-08T06:13:12.207Z
@MichaelSohnen you can not, it has an answer. But why don't you write your own answer?
joojaa
CC BY-SA 4.0
2021-09-07T11:38:27.397Z
2021-09-07T11:38:27.397Z
dubious
<p>Dear Computer Graphics SE,</p>
<p>I have a RAYMARCHING renderer, that looks up voxel data from a 3D texture. Each cell in the texture can be 0 or 1.</p>
<p>I have a very simple algorithm for calculating the signed distance at a given point p in space. Here is some pseudocode</p>
<pre><code>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
</code></pre>
<p>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.</p>
<p>Here is my normal algorithm (glsl):</p>
<pre><code>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;



}
</code></pre>
<p>What is the best way to get a good sdf for my voxel field, that won't break the normals?</p>

<glsl><voxelization><raymarching><signed-distance-field>
Ray-Marching: Rendering a Voxel Grid with Proper Normals
Michael Sohnen
# Ray-Marching: Rendering a Voxel Grid with Proper Normals

(Asked by: username_0 on 2021-08-18)

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?

**Tags:** glsl, voxelization, raymarching, signed-distance-field


---

## 1 answers

### Answer by username_1 on 2021-09-07. Score: 0

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.

> **Comments:**
> **username_0**: 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.  
> **username_2**: @username_0 you can not, it has an answer. But why don't you write your own answer?  

---

