How to draw isoline without transition color

I’m trying to draw several black isoline at vertex y length = 0.2 and 0.5 and 0.7 based on this example: IsoNoise (Icosahedron + Perlin noise + Isolines + SelectiveBloom)
. But I got transition color between black and other colors. How could I get the exactly isoline ?

shader code

 fragmentShader: `
   #define ss(a, b, c) smoothstep(a, b, c)
    uniform float minHeight;
    uniform float maxHeight;
    uniform sampler2D heightTexture;
    varying float h;
    varying vec3 vertex;

    vec3 isolineColor = vec3(0.0, 0.0, 1.0); // Blue color
    vec3 spaceColorPink = vec3(1.0, 0.0, 1.0); // Pink color
    vec3 spaceColorYellow = vec3(1.0, 1.0, 0.0); // Yellow color

    void main(){

      // Calculate the length of vertex.y
      float vertexYLength = length(vertex.y);

      // Define isoline color as black
      vec3 isolineColor = vec3(0.0, 0.0, 0.0); // Black isoline color
      
      // Calculate smoothstep values for color transitions
      float t1 = smoothstep(0.0, 0.2, vertexYLength);
      float t2 = smoothstep(0.2, 0.5, vertexYLength);
      float t3 = smoothstep(0.5, 0.7, vertexYLength);
      
      // Set colors based on smoothstep values
      vec3 color;
      if (vertexYLength < 0.2) {
          color = mix(vec3(1.0, 0.0, 0.0), isolineColor, t1); // Red
      } else if (vertexYLength < 0.5) {
          color = mix(vec3(0.0, 0.0, 1.0), isolineColor, t2); // Blue
      } else if (vertexYLength < 0.7) {
          color = mix(vec3(1.0, 1.0, 0.0), isolineColor, t3); // Yellow
      } else {
          color = vec3(0.0, 1.0, 0.0); // Green
      }
      
      // Set the final color for the fragment
      gl_FragColor = vec4(color, 1.0);

    } 
  `

If this is good enough:

then use this sequence of 'if'-s:

      // Set colors based on smoothstep values
      vec3 color;
      if (vertexYLength < 0.19) {
          color = vec3(1.0, 0.0, 0.0);
      } else if (vertexYLength < 0.21) {
        color = isolineColor;
      } else if (vertexYLength < 0.49) {
        color = vec3(0.0, 0.0, 1.0);
      } else if (vertexYLength < 0.51) {
        color = isolineColor;
      } else if (vertexYLength < 0.69) {
        color = vec3(1.0, 1.0, 0.0);
      } else if (vertexYLength < 0.71) {
        color = isolineColor;
      } else {
        color = vec3(0.0, 1.0, 0.0);
      }

Note that many people say shaders hate 'if' statements and suggest to eliminate them at any cost. My opinion is that for simple cases there is no problem with 'if'. It should be dealt with only if it really makes performance issues.

Thank you so much, this is I want to get the result, this is just a simple example for codeSandBox, but for my project, YLength function is y = 10/ x , if x is really large that will result in very very thick isoline.

Of course, the idea should not be used verbatim in a more complex environment. You have to adapt it to suit your needs. Think of the code as a demo of how to make isolines without color transition (as it is the original question).

For example, the following part of the code defines an isoline between 0.19 and 0.21. If you want narrower line, you can change the numbers to 0.195 and 0.205. So the width is up to you.

However, if you have many levels of isolines, it is better to use a formula to calculate any isoline, instead of checking them one by one. Or you can try with textures, as in this example: https://codepen.io/boytchev/full/gOQQRLd

2 Likes

Thank you so much for your idea, I will use formula to calculate isolines for my case.

1 Like

As usual, I’m late to the party :slight_smile:

This is equal to abs(vertex.y)

Having not so many values for colors and heights, you can use a loop in fragment shader to paint the heights and to draw the isolines :thinking:

Demo: zealous-architecture-t5s4fm - CodeSandbox

PS Not the ultimate solution, just an example.

3 Likes

Thank you so much for your genius solution. A little bit late but really helpful to me. Thanks again. :slightly_smiling_face:

1 Like