I have this: terrain

(Right now I have the height map in a x*x size 2D array and a 1D vector too.)

What I am trying to achieve is something like this: target Without using any textures, only plain colors. So basically smooth transitions and some shadow (using shaders). My vertex shader looks like this:

    #version 330 
    layout (location = 0) in vec3 Position;
    layout (location = 1) in vec3 Normal;
    layout (location = 2) in vec3 Color;

    out vec3 fragmentNormal;
    out vec4 ex_color,pos;
    out vec3 N;
    out vec3 v;

    void main () {
    pos= vec4(Position,1);
    ex_color = vec4(Color,1);   
    fragmentNormal = Normal;

    v = vec3(gl_ModelViewMatrix * pos);       
    N = normalize(gl_NormalMatrix * Normal);

    gl_Position = gl_ModelViewProjectionMatrix * vec4(Position,1);

I have normals for all the vertices. Color is set simply in the c++ code based on height.

Here is the fragment shader

    in vec3 N;
    in vec3 v;
    in vec4 ex_color;
    void main(void)
       vec3 L = normalize(gl_LightSource[0].position.xyz - v);   
       vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);  
       Idiff = clamp(Idiff, 0.0, 1.0); 
       gl_FragColor = Idiff*ex_color;

So I guess my problem is what formula should I use to mix the colors. I think I don't need to set the colors in the c++ code but in the shaders.

Update: Here is the wireframe of the terrain. wireframe

Update2: Based on @Babis' answer the result is: enter image description here

So the gradient is not "projected" onto the surface as I would like to do. What could cause this? Maybe my qustion wasn't clear.

  • \$\begingroup\$ there's a difference between screen Y (what you appear to use for that last pic) and world Y (what you want to use) \$\endgroup\$ Nov 3, 2014 at 11:22

1 Answer 1


It's a simple interpolation. Let's assume that your heights span -1 to 1, 0 is water surface and you have 3 colours: dark green, light green and white. A way to do what you want is to have the following color_from_height function in the pixel or fragment shader (depending on how efficient you want to be). In my shader below I visualize the gradient, but the function color_from_height should get the world space height.

// This is a shadertoy example (www.shadertoy.com) which will visualize the 4-colours palette

vec3 color_from_height( const float height )
    vec3 terrain_colours[4];
    terrain_colours[0] = vec3(0.0,0.0,0.6);
    terrain_colours[1] = vec3(0.1, 0.3, 0.1);
    terrain_colours[2] =  vec3(0.4, 0.8, 0.4);
    terrain_colours[3] = vec3(1.0,1.0,1.0);
    //vec3 terrain_colours[1] = vec3[1]{ vec3(0,0,0.6)};
    if(height < 0.0)
        return terrain_colours[0];
        float hscaled = height*2.0 - 1e-05; // hscaled should range in [0,2)
        int hi = int(hscaled); // hi should range in [0,1]
        float hfrac = hscaled-float(hi); // hfrac should range in [0,1]
        if( hi == 0)
            return mix( terrain_colours[1],terrain_colours[2],hfrac); // blends between the two colours    
            return mix( terrain_colours[2],terrain_colours[3],hfrac); // blends between the two colours
    return vec3(0.0,0.0,0.0);

void main(void)
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    vec3 col = color_from_height(uv.y*2.0-1.0);
    gl_FragColor = vec4(col,1.0);
  • 1
    \$\begingroup\$ you misunderstood my answer, the height that you need to provide is the "world space height". the screen space height that I used was to visualize the gradient :) \$\endgroup\$
    – Babis
    Nov 3, 2014 at 11:06
  • \$\begingroup\$ Thanks I got it :) Now I need to rescale my terrain to [0,1] or modify your solution to my range :) What would you prefer? \$\endgroup\$
    – Zoltantan
    Nov 3, 2014 at 17:01
  • \$\begingroup\$ None of the two, really :) you can provide in the shader the maximum height and "normalize" the provided height: norm_height = height/max_height; color_from_height( norm_height ); That way you barely do any changes. \$\endgroup\$
    – Babis
    Nov 3, 2014 at 17:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .