Terrain Shader, do something based on distance from camera?

So I’m trying to make an adjustment to my Terrain shader and I’m not exactly sure where to start here. Basically I have two variables I’m currently setting in the inspector (_SplatIntensity and _SplatScaledIntensity). Instead I’d really like to have these variables set by how far from the camera the given vertex is. In the end it would look something like this:

ground right at camera? _SplatIntensity == 1, _SplatScaledIntensity == 0
== lerp to ==
ground at 500 units away? _SplatIntensity == 0.6, _SplatScaledIntensity == 0.4

Any thoughts on how I could accomplish this would be greatly appreciated!

Shader "Sortasoft/Terrain/Sorta Bumped Specular" {
Properties {
    _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
    //_Shininess ("Shininess", Range (0.03, 1)) = 0.078125
    _SplatScale ("Splat Scale", Range (-1, 1)) = -0.125
    _SplatIntensity ("Splat Intensity", Range (0, 1)) = 0.6
    _SplatScaledIntensity ("Splat Scaled Intensity", Range(0, 1)) = 0.4
    
    // set by terrain engine
    [HideInInspector] _Control ("Control (RGBA)", 2D) = "red" {}
    [HideInInspector] _Splat3 ("Layer 3 (A)", 2D) = "white" {}
    [HideInInspector] _Splat2 ("Layer 2 (B)", 2D) = "white" {}
    [HideInInspector] _Splat1 ("Layer 1 (G)", 2D) = "white" {}
    [HideInInspector] _Splat0 ("Layer 0 (R)", 2D) = "white" {}
    [HideInInspector] _Normal3 ("Normal 3 (A)", 2D) = "bump" {}
    [HideInInspector] _Normal2 ("Normal 2 (B)", 2D) = "bump" {}
    [HideInInspector] _Normal1 ("Normal 1 (G)", 2D) = "bump" {}
    [HideInInspector] _Normal0 ("Normal 0 (R)", 2D) = "bump" {}
    // used in fallback on old cards  base map
    [HideInInspector] _MainTex ("BaseMap (RGB)", 2D) = "white" {}
    [HideInInspector] _Color ("Main Color", Color) = (1,1,1,1)
    
    // Smude Map
    _SmudgeMap ("Smudge Map", 2D) = "white" {}
}
    
SubShader {
    Tags {
        "SplatCount" = "4"
        "Queue" = "Geometry-100"
        "RenderType" = "Opaque"
    }
    CGPROGRAM
    #pragma surface surf BlinnPhong vertex:vert
    #pragma target 3.0

    void vert (inout appdata_full v)
    {
        v.tangent.xyz = cross(v.normal, float3(0,0,1));
        v.tangent.w = -1;
    }

    struct Input {
        float2 uv_Control : TEXCOORD0;
        float2 uv_Splat0 : TEXCOORD1;
        float2 uv_Splat1 : TEXCOORD2;
        float2 uv_Splat2 : TEXCOORD3;
        float2 uv_Splat3 : TEXCOORD4;
    };

    sampler2D _Control;
    sampler2D _Splat0,_Splat1,_Splat2,_Splat3;
    sampler2D _Normal0,_Normal1,_Normal2,_Normal3;
    sampler2D _SmudgeMap;
    half _SplatScale;
    half _SplatIntensity;
    half _SplatScaledIntensity;
    //half _Shininess;

    void surf (Input IN, inout SurfaceOutput o) {
        fixed4 splat_control = tex2D (_Control, IN.uv_Control);
        fixed4 col;
        col  = splat_control.r * (tex2D (_Splat0, IN.uv_Splat0) *_SplatIntensity + tex2D (_Splat0, IN.uv_Splat0 * _SplatScale) * _SplatScaledIntensity);
        col += splat_control.g * (tex2D (_Splat1, IN.uv_Splat1) *_SplatIntensity + tex2D (_Splat1, IN.uv_Splat1 * _SplatScale) * _SplatScaledIntensity);
        col += splat_control.b * (tex2D (_Splat2, IN.uv_Splat2) *_SplatIntensity + tex2D (_Splat2, IN.uv_Splat2 * _SplatScale) * _SplatScaledIntensity);
        col += splat_control.a * (tex2D (_Splat3, IN.uv_Splat3) *_SplatIntensity + tex2D (_Splat3, IN.uv_Splat3 * _SplatScale) * _SplatScaledIntensity);
        
        //col  = splat_control.r * tex2D (_Splat0, IN.uv_Splat0) * (1 - tex2D (_SmudgeMap, IN.uv_Splat0 * _SplatScale) * _SplatIntensity);
        //col += splat_control.g * tex2D (_Splat1, IN.uv_Splat1) * (1 - tex2D (_SmudgeMap, IN.uv_Splat1 * _SplatScale) * _SplatIntensity);
        //col += splat_control.b * tex2D (_Splat2, IN.uv_Splat2) * (1 - tex2D (_SmudgeMap, IN.uv_Splat2 * _SplatScale) * _SplatIntensity);
        //col += splat_control.a * tex2D (_Splat3, IN.uv_Splat3) * (1 - tex2D (_SmudgeMap, IN.uv_Splat3 * _SplatScale) * _SplatIntensity);
        
        //col  = splat_control.r * tex2D (_SmudgeMap, IN.uv_Control * -1.75);
        //col += splat_control.g * tex2D (_SmudgeMap, IN.uv_Control * -1.75);
        //col += splat_control.b * tex2D (_SmudgeMap, IN.uv_Control * -1.75);
        //col += splat_control.a * tex2D (_SmudgeMap, IN.uv_Control * -1.75);
        
        //col *= tex2D (_SmudgeMap, IN.uv_Control);
        
        o.Albedo = col.rgb;

        fixed4 nrm;
        nrm  = splat_control.r * tex2D (_Normal0, IN.uv_Splat0);
        nrm += splat_control.g * tex2D (_Normal1, IN.uv_Splat1);
        nrm += splat_control.b * tex2D (_Normal2, IN.uv_Splat2);
        nrm += splat_control.a * tex2D (_Normal3, IN.uv_Splat3);
        // Sum of our four splat weights might not sum up to 1, in
        // case of more than 4 total splat maps. Need to lerp towards
        // "flat normal" in that case.
        fixed splatSum = dot(splat_control, fixed4(1,1,1,1));
        fixed4 flatNormal = fixed4(0.5,0.5,1,0.5); // this is "flat normal" in both DXT5nm and xyz*2-1 cases
        nrm = lerp(flatNormal, nrm, splatSum);
        o.Normal = UnpackNormal(nrm);

        o.Gloss = col.a * splatSum;
        //o.Specular = _Shininess;

        o.Alpha = 0.0;
    }
    ENDCG  
}

Dependency "AddPassShader" = "Hidden/Sortasoft/Terrain/Sorta Bumped Specular Add Pass"
Dependency "BaseMapShader" = "Specular"

Fallback "Nature/Terrain/Diffuse"
}
1 Like

Hi,

Add a field to your vertex output structure like so:-

float  wrldDistance;

In your vertex shader do something like this:-

 out.wrldDistance = distance(_WorldSpaceCameraPos, mul(_Object2World, v.vertex));

wrldDistance will then be interpolated per pixel and available in your surface shader for calculations.

btw _WorldSpaceCameraPos is filled out by Unity. It is one of their built-in shader values.

http://docs.unity3d.com/Documentation/Components/SL-BuiltinValues.html

1 Like

Hi Gaski! Sorry for the late response, but I wanted to let you know that your response was perfect - got it working exactly the way I want!

Thanks so much!