<p>Alright, so the issue was that the shader is a multipass one, so before detecting edges I exported my noise into a 2d sampler at which point it seems it loses some (a lot of) precision.</p>
<p>So I went to packing/unpacking float (e.g. as described here <a href="https://stackoverflow.com/questions/13005391/loss-of-precision-in-glsl-fragment-shader">https://stackoverflow.com/questions/13005391/loss-of-precision-in-glsl-fragment-shader</a>).</p>
<p>With this approach I was able to get this much of topo lines (again, purple line shows 1 km):
<a href="https://i.sstatic.net/i8a29.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/i8a29.png" alt="enter image description here" /></a></p>
<p>There are some artifacts here, but I'm sure it's just a matter of coefficients.</p>

CC BY-SA 4.0
2024-01-25T20:28:27.357Z
Actually the crossing line artifact originated from here: https://github.com/ashima/webgl-noise/issues/21#issuecomment-698454072
wcobalt
CC BY-SA 4.0
2024-01-25T18:22:24.773Z
2024-01-25T18:22:24.773Z
wcobalt
<p>I'm working on a game that has a big proc. generated map (10000km by 20000km). The map generation is based on multi-octave perlin noise.</p>
<pre><code>...
vec2 step = vec2(1.3, 1.7);
float n = 0.0;
n += color(uv.xy, t);
n += 0.5 * color(uv.xy * 2.0 - step, t);
n += 0.25 * color(uv.xy * 4.0 - 2.0 * step, t);
n += 0.125 * color(uv.xy * 8.0 - 3.0 * step, t);
n += 0.0625 * color(uv.xy * 16.0 - 4.0 * step, t);
n += 0.03125 * color(uv.xy * 32.0 - 5.0 * step, t);
n += 0.015625 * color(uv.xy * 64.0 - 6.0 * step, t);
n += 0.0078125 * color(uv.xy * 128.0 - 7.0 * step, t);
n += 0.00390625 * color(uv.xy * 256.0 - 8.0 * step, t);
n += (0.00390625 / 2.0) * color(uv.xy * (256.0 * 2.0) - (8.0 * 2.0) * step, t);
n += (0.00390625 / 4.0) * color(uv.xy * (256.0 * 4.0) - (8.0 * 4.0) * step, t);
n += (0.00390625 / 8.0) * color(uv.xy * (256.0 * 8.0) - (8.0 * 8.0) * step, t);
n += (0.00390625 / 16.0) * color(uv.xy * (256.0 * 16.0) - (8.0 * 16.0) * step, t);
n += (0.00390625 / 32.0) * color(uv.xy * (256.0 * 32.0) - (8.0 * 32.0) * step, t);
n += (0.00390625 / 64.0) * color(uv.xy * (256.0 * 64.0) - (8.0 * 64.0) * step, t);
n += (0.00390625 / 128.0) * color(uv.xy * (256.0 * 128.0) - (8.0 * 128.0) * step, t);
n += (0.00390625 / 256.0) * color(uv.xy * (256.0 * 256.0) - (8.0 * 256.0) * step, t);
n += (0.00390625 / 512.0) * color(uv.xy * (256.0 * 512.0) - (8.0 * 512.0) * step, t);
n += (0.00390625 / 1024.0) * color(uv.xy * (256.0 * 1024.0) - (8.0 * 1024.0) * step, t);
...
</code></pre>
<p>Showing the noise's code just to give an idea about the size of small values in use.</p>
<p>The goal here is to render the map as topo lines, each one representing small change in terrain height.</p>
<p><a href="https://i.sstatic.net/lXRON.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/lXRON.png" alt="enter image description here" /></a></p>
<p>This is the current result.</p>
<p>The screenshot below spans for about 19000 kms<a href="https://i.sstatic.net/lzhU4.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/lzhU4.png" alt="enter image description here" /></a></p>
<p>This one for about 50 kms (the purple line shows what 1km looks like)</p>
<p><a href="https://i.sstatic.net/6yZYJ.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/6yZYJ.png" alt="enter image description here" /></a></p>
<p>As you can see the closer we get to the ground the less topo lines we get, which is not what I want. My goal is to have high precision topo lines even at small scales like few kilometers.</p>
<p>I use the following GLSL code to detect edges:</p>
<pre><code>const float STEPS = 10000000.;

const mat3 EDGE_KERNEL = mat3(
    -1, -1, -1,
    -1,  8, -1,
    -1, -1, -1
);

float discretize(float value, float offset) {
    return floor(value * float(STEPS) + offset) / float(STEPS);
}

float tex(vec2 p) {
    return discretize(texture2D(heightmap, p).x, .5);
}
...
//outlines
float edge = 0.;
for (int i = 0; i &lt; 3; i++) {
    for (int j = 0; j &lt; 3; j++) {
        vec2 offset = vec2(float(j - 1), float(i - 1)) / resolution.xy;
        vec2 texCoord = uv + offset;
        edge += 1. / tex(texCoord) * EDGE_KERNEL[j][i];
    }
}
vec3 outlineMask = edge &gt; 0.01 ? vec3(0.) : vec3(1.);
...
</code></pre>
<p>Unfortunately, I cannot provide the full code or even stripped one since it's pretty hard to strip this code, but I'm ready to provide any details necessary.</p>
<p>The question is why the edges are not being detected for small float differences. I tried different values in the <code>edge &gt; 0.01</code> condition, but no good results there either.</p>
<p>Did I hit the float precision limit, or is it my noise (it looks like it has enough octaves to give the actual differences to those height), or is it the edge detection algo I use?</p>

<glsl>
Detecting edges on really small float-value differences
wcobalt
# Detecting edges on really small float-value differences

(Asked by: username_0 on 2024-01-25)

I'm working on a game that has a big proc. generated map (10000km by 20000km). The map generation is based on multi-octave perlin noise.

```
...
vec2 step = vec2(1.3, 1.7);
float n = 0.0;
n += color(uv.xy, t);
n += 0.5 * color(uv.xy * 2.0 - step, t);
n += 0.25 * color(uv.xy * 4.0 - 2.0 * step, t);
n += 0.125 * color(uv.xy * 8.0 - 3.0 * step, t);
n += 0.0625 * color(uv.xy * 16.0 - 4.0 * step, t);
n += 0.03125 * color(uv.xy * 32.0 - 5.0 * step, t);
n += 0.015625 * color(uv.xy * 64.0 - 6.0 * step, t);
n += 0.0078125 * color(uv.xy * 128.0 - 7.0 * step, t);
n += 0.00390625 * color(uv.xy * 256.0 - 8.0 * step, t);
n += (0.00390625 / 2.0) * color(uv.xy * (256.0 * 2.0) - (8.0 * 2.0) * step, t);
n += (0.00390625 / 4.0) * color(uv.xy * (256.0 * 4.0) - (8.0 * 4.0) * step, t);
n += (0.00390625 / 8.0) * color(uv.xy * (256.0 * 8.0) - (8.0 * 8.0) * step, t);
n += (0.00390625 / 16.0) * color(uv.xy * (256.0 * 16.0) - (8.0 * 16.0) * step, t);
n += (0.00390625 / 32.0) * color(uv.xy * (256.0 * 32.0) - (8.0 * 32.0) * step, t);
n += (0.00390625 / 64.0) * color(uv.xy * (256.0 * 64.0) - (8.0 * 64.0) * step, t);
n += (0.00390625 / 128.0) * color(uv.xy * (256.0 * 128.0) - (8.0 * 128.0) * step, t);
n += (0.00390625 / 256.0) * color(uv.xy * (256.0 * 256.0) - (8.0 * 256.0) * step, t);
n += (0.00390625 / 512.0) * color(uv.xy * (256.0 * 512.0) - (8.0 * 512.0) * step, t);
n += (0.00390625 / 1024.0) * color(uv.xy * (256.0 * 1024.0) - (8.0 * 1024.0) * step, t);
...

```

Showing the noise's code just to give an idea about the size of small values in use.

The goal here is to render the map as topo lines, each one representing small change in terrain height.

[![enter image description here](https://i.sstatic.net/lXRON.png)](https://i.sstatic.net/lXRON.png)

This is the current result.

The screenshot below spans for about 19000 kms[![enter image description here](https://i.sstatic.net/lzhU4.png)](https://i.sstatic.net/lzhU4.png)

This one for about 50 kms (the purple line shows what 1km looks like)

[![enter image description here](https://i.sstatic.net/6yZYJ.png)](https://i.sstatic.net/6yZYJ.png)

As you can see the closer we get to the ground the less topo lines we get, which is not what I want. My goal is to have high precision topo lines even at small scales like few kilometers.

I use the following GLSL code to detect edges:

```
const float STEPS = 10000000.;

const mat3 EDGE_KERNEL = mat3(
    -1, -1, -1,
    -1,  8, -1,
    -1, -1, -1
);

float discretize(float value, float offset) {
    return floor(value * float(STEPS) + offset) / float(STEPS);
}

float tex(vec2 p) {
    return discretize(texture2D(heightmap, p).x, .5);
}
...
//outlines
float edge = 0.;
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        vec2 offset = vec2(float(j - 1), float(i - 1)) / resolution.xy;
        vec2 texCoord = uv + offset;
        edge += 1. / tex(texCoord) * EDGE_KERNEL[j][i];
    }
}
vec3 outlineMask = edge > 0.01 ? vec3(0.) : vec3(1.);
...

```

Unfortunately, I cannot provide the full code or even stripped one since it's pretty hard to strip this code, but I'm ready to provide any details necessary.

The question is why the edges are not being detected for small float differences. I tried different values in the `edge > 0.01` condition, but no good results there either.

Did I hit the float precision limit, or is it my noise (it looks like it has enough octaves to give the actual differences to those height), or is it the edge detection algo I use?

**Tags:** glsl


---

## 1 answers

### Answer by username_0 on 2024-01-25. Score: 0 | Accepted answer

Alright, so the issue was that the shader is a multipass one, so before detecting edges I exported my noise into a 2d sampler at which point it seems it loses some (a lot of) precision.

So I went to packing/unpacking float (e.g. as described here <https://stackoverflow.com/questions/13005391/loss-of-precision-in-glsl-fragment-shader>).

With this approach I was able to get this much of topo lines (again, purple line shows 1 km):
[![enter image description here](https://i.sstatic.net/i8a29.png)](https://i.sstatic.net/i8a29.png)

There are some artifacts here, but I'm sure it's just a matter of coefficients.

> **Comments:**
> **username_0**: Actually the crossing line artifact originated from here: https://github.com/ashima/webgl-noise/issues/21#issuecomment-698454072  

---

