Search code examples
colorsthree.jsglslshaderfragment-shader

How to make elevated parts of a steep plane seem darker than the lower surface?


I made a plane in THREEjs using Mesh, PlaneGeometry and ShaderMaterial. It's a very simple/basic form. I applied a simple phormula to make the plain more steep. Now I'm trying to make the lower surface darker than the higher surface. Here is what I tried.

Vertex shader:

    varying vec3 test;

    void main(void) {
        float amp = 2.5;
        float z = amp * sin(position.x*0.2)  * cos(position.y*0.5); //this makes the surface steeper
        test = vec3(1, 1, -z); //this goes to fragment shader
        //test = vec3(698.0, 400.0, -z); I have tried this. first coordenates here are to normalize the vector

        gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x, position.y, z, 1.0);
    }

Fragment shader:

    precision mediump float;
    varying vec3 test;
    void main(void) {   
        vec3 st = gl_FragCoord.xyz/test;
        gl_FragColor = vec4(st.xyz, 1.0);
    }

Result:

enter image description here

This result is not desirable, since the contrast between top and down is too aggressive and I'd like the lower surface less white. What do I have to change to accomplish this?


Solution

  • If you want to create a brightness based on the height of the waves, then you'll need to only use the test.z value, since test.xy aren't really doing anything. The problem is that brightness needs a value between [0, 1] and due to the amplitude multiplication, you're getting a value between [-2.5, 2.5] range.

    precision mediump float;
    varying vec3 test;
    void main(void) {
        float amp = 2.5;
    
        // Extract brightness from test.z
        float brightness = test.z;
    
        // Convert brightness from [-2.5, 2.5] to [0.0, 1.0] range
        brightness = (brightness / amp) * 0.5 + 0.5;
    
        vec3 yellow = vec3(1.0, 1.0, 0.0);
    
        // Multiply final color by brigthness (0 brightness = black)
        vec3 st = yellow * brightness;
        gl_FragColor = vec4(st.xyz, 1.0);
    }
    

    That should give you a smoother transition from full yellow to black.

    As an aside, to help me visualize the values I'm getting from GLSL functions, I like to use the Graphtoy tool. I recommend you give it a shot to help you write shaders!