Godot 3.0; the new way to make a terrain shader (with normal maps)

Ace DragonAce Dragon Posts: 74Member
edited September 2017 in Resources

Shader script (since 3.0 doesn't have visual nodes yet).

shader_type spatial;
//color textures
uniform sampler2D color_texture1;
uniform sampler2D color_texture2;
uniform sampler2D color_texture3;
uniform sampler2D color_texture4;
//normal textures
uniform sampler2D normal_texture1;
uniform sampler2D normal_texture2;
uniform sampler2D normal_texture3;
uniform sampler2D normal_texture4;
//normalmap strength and texture scale
uniform float normalMap_strength = 1.0;
uniform float texture_scale = 1;

void fragment(){
    //scale the UV's according to the scale uniform
    vec2 finalUV = UV*texture_scale;

    // get the individual color channels in our vertex colors
    float blueChannel = COLOR[2];
    float greenChannel = COLOR[1];
    float redChannel = COLOR[0];

    //get the textures that we will use
    vec3 TexBlue = texture(color_texture1, finalUV).rgb;
    vec3 TexGreen = texture(color_texture2, finalUV).rgb;
    vec3 TexRed = texture(color_texture3, finalUV).rgb;
    vec3 TexBlack = texture(color_texture4, finalUV).rgb;

    //normal textures
    vec3 NormalTexBlue = texture(normal_texture1, finalUV).rgb;
    vec3 NormalTexGreen = texture(normal_texture2, finalUV).rgb;
    vec3 NormalTexRed = texture(normal_texture3, finalUV).rgb;
    vec3 NormalTexBlack = texture(normal_texture4, finalUV).rgb;

    //mix the textures together using those color channels as masks
    vec3 mixed1 = mix(TexBlack,TexRed,redChannel);
    vec3 mixed2 = mix(mixed1,TexGreen,greenChannel);
    vec3 finalMix = mix(mixed2,TexBlue,blueChannel);

    //mix the normal textures together using those color channels as masks
    vec3 mixedNormal1 = mix(NormalTexBlack,NormalTexRed,redChannel);
    vec3 mixedNormal2 = mix(mixedNormal1,NormalTexGreen,greenChannel);
    vec3 finalNormalMix = mix(mixedNormal2,NormalTexBlue,blueChannel);

    //apply the texture mixes and strength
    ALBEDO = finalMix;
    //NORMAL = normalize(NORMAL*(finalNormalMix*normalMap_strength));
    NORMALMAP = finalNormalMix;
    NORMALMAP_DEPTH = normalMap_strength;
    }

Still a few things missing (specularity and hardness ect...), but this should be a good starting point for those who want to create games with terrain in the new version. Personally, I really like how applying normal maps seem far more straightforward now (there's no artifacts that appear when panning around).

You will need tangent space normal maps and a mesh with vertex colors for this to work.

Enjoy :)

Comments

  • Ace DragonAce Dragon Posts: 74Member
    edited April 15

    Actually, I noticed the code would produce visible issues are far as lighting goes.

    With the help of what I gleaned when converting Spatial Materials to Shader scripts (and copying the above over to a project of mine). I got this.

    shader_type spatial;
    render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx;
    //Color Textures
    uniform sampler2D color_texture1: hint_albedo;
    uniform sampler2D color_texture2: hint_albedo;
    uniform sampler2D color_texture3: hint_albedo;
    uniform sampler2D color_texture4: hint_albedo;
    //Normal Textures
    uniform sampler2D normal_texture1: hint_normal;
    uniform sampler2D normal_texture2: hint_normal;
    uniform sampler2D normal_texture3: hint_normal;
    uniform sampler2D normal_texture4: hint_normal;
    //normal map strength and texture scale
    uniform float normalMap_strength = 1.0;
    uniform float texture_scale = 1.0;
    
    void fragment(){
    
        vec2 finalUV = UV*texture_scale;
    
        // get the individual color channels in our vertex colors
        float blueChannel = COLOR[2];
        float greenChannel = COLOR[1];
        float redChannel = COLOR[0];
    
        //get the textures that we will use
        vec3 TexBlue = texture(color_texture1, finalUV).rgb;
        vec3 TexGreen = texture(color_texture2, finalUV).rgb;
        vec3 TexRed = texture(color_texture3, finalUV).rgb;
        vec3 TexBlack = texture(color_texture4, finalUV).rgb;
    
        vec3 newTexGreen = vec3(TexGreen[0]-(TexGreen[0]*0.2),TexGreen[1]-(TexGreen[1]*0.2),TexGreen[2]-(TexGreen[2]*0.3));
    
        //normal textures
        vec3 NormalTexBlue = texture(normal_texture1, finalUV).rgb;
        vec3 NormalTexGreen = texture(normal_texture2, finalUV).rgb;
        vec3 NormalTexRed = texture(normal_texture3, finalUV).rgb;
        vec3 NormalTexBlack = texture(normal_texture4, finalUV).rgb;
    
        //mix the textures together using those color channels as masks
        vec3 mixed1 = mix(TexBlack,TexRed,redChannel);
        vec3 mixed2 = mix(mixed1,newTexGreen,greenChannel);
        vec3 finalMix = mix(mixed2,TexBlue,blueChannel);
    
        //mix the normal textures together using those color channels as masks
        vec3 mixedNormal1 = mix(NormalTexBlack,NormalTexRed,redChannel);
        vec3 mixedNormal2 = mix(mixedNormal1,NormalTexGreen,greenChannel);
        vec3 finalNormalMix = mix(mixedNormal2,NormalTexBlue,blueChannel);
    
        //apply the texture mix
        ALBEDO = finalMix;
    
        //apply the other key attributes
        SPECULAR = 0.0;
        METALLIC = 0.0;
    
        //NORMAL = normalize(NORMAL*(finalNormalMix*normalMap_strength));
        NORMALMAP = finalNormalMix;
        NORMALMAP_DEPTH = normalMap_strength;
        }
    

    Turns out the little hint thingies are a very important component, applying those means those who use this script will now have correct lighting.

Sign In or Register to comment.