Terrain Details Blurry

I am trying to go for a crisp pixelated look for textures but when it comes to terrain, the grass I add on the details layer is all blurry even though the texture is set to “on point” and looks fine if used anywhere else

I’ve seen this question asked multiple times but never solved.
In one thread it was suggested that the terrain component creates his own material under the hood for the details. If that’s the case how can I address it to get the desired result?

I’m using unity 2018.4.10f1 if that matters

You can download unity standard shaders source and drag the terrain shader into your project…
then open the terrain shader and the end of the shader you can change degenderizes shader path(detail shader)
line 54 55 56

root of the shaders:

Thanks for the response!

I am not sure if I’m doing it correctly:
I copied the FirstPass.shader to my project and created a new material from it and assigned to my terrain.
Any change I make to lines 54,55,56 doesn’t affect my grass on the detail layer at all. Even if I remove the lines nothing changes.

I’m not that good with shaders so I would appreciate if you could elaborate on what I should do with these lines

This is a simple solution:
Create a shader with the below name in your project:

Shader "Hidden/TerrainEngine/Details/WavingDoublePass"

Now your grass shader is this created shader

you must control grass shader properties using script

Example shader:

Shader "Hidden/TerrainEngine/Details/WavingDoublePass"
{
    Properties
    {
        _Cutoff( "Mask Clip Value", Float ) = 0.5
        [Header(Translucency)]
        _Grass_Translucency("Strength", Range( 0 , 50)) = 1
        _TransNormalDistortion("Normal Distortion", Range( 0 , 1)) = 0.1
        _TransScattering("Scaterring Falloff", Range( 1 , 50)) = 2
        _TransDirect("Direct", Range( 0 , 1)) = 1
    //    _Grass_TransAmbient("Ambient", Range( 0 , 1)) = 0.2
        //_Grass_TransShadow("Shadow", Range( 0 , 1)) = 0.9
        _MainTex("MainTex", 2D) = "white" {}
        _Grass_Translucency_10_x_multiplier("Translucency_10_x_multiplier", Float) = 10
                [Header(Wind Settings)]
        // Wave mode leave
        _MinY("Minimum Y Value", Range(-5,0)) = -1

        _xScale ("X Amount", Range(-0.2,0.2)) = 0.5
        _yScale ("Z Amount", Range(-0.2,0.2)) = 0.5
        [HideInInspector] _texcoord( "", 2D ) = "white" {}
        [HideInInspector] __dirty( "", Int ) = 1
    }

    SubShader
    {
        Tags{ "RenderType" = "TransparentCutout"  "Queue" = "AlphaTest+0" }
        Cull Off
        CGPROGRAM
        #include "UnityPBSLighting.cginc"
        #pragma target 3.0
        #pragma surface surf StandardSpecularCustom keepalpha addshadow fullforwardshadows exclude_path:deferred  vertex:vert
        struct Input
        {
            float2 uv_texcoord;
        };

        struct SurfaceOutputStandardSpecularCustom
        {
            fixed3 Albedo;
            fixed3 Normal;
            half3 Emission;
            fixed3 Specular;
            half Smoothness;
            half Occlusion;
            fixed Alpha;
            fixed3 Translucency;
        };

        uniform float4 _Grass_Color;
        uniform sampler2D _MainTex;
        uniform float4 _MainTex_ST;
        uniform float4 Grass_Specular_Color;
        uniform float _Grass_Smoothness;
        uniform half _Grass_Translucency;
        uniform half _TransNormalDistortion;
        uniform half _TransScattering;
        uniform half _TransDirect;
        uniform half _Grass_TransAmbient;
        uniform half _Grass_TransShadow;
        uniform float _Grass_Translucency_Intensity;
        uniform float _Grass_Translucency_10_x_multiplier;
        uniform float4 _Grass_Translucency_Color;
        uniform float _Cutoff = 0.5;
        float _MinY;
        float _xScale;
        float _yScale;
        float _Grass_Wind_Scale;
        float _Grass_Wind_Speed;
        float _Grass_World_Scale;
        float _Amount;

        void vert (inout appdata_full v)
        {
            float num = v.vertex.z;

            if ((num-_MinY) > 0.0) {
                float3 worldPos = mul (unity_ObjectToWorld, v.vertex).xyz;
                float x = sin(worldPos.x/_Grass_World_Scale + (_Time.y*_Grass_Wind_Speed)) * (num-_MinY) * _Grass_Wind_Scale * 0.01;
                float y = sin(worldPos.y/_Grass_World_Scale + (_Time.y*_Grass_Wind_Speed)) * (num-_MinY) * _Grass_Wind_Scale * 0.01;

                v.vertex.x += x * _xScale;
                v.vertex.y += y * _yScale;
            }
        }


        inline half4 LightingStandardSpecularCustom(SurfaceOutputStandardSpecularCustom s, half3 viewDir, UnityGI gi )
        {
            #if !DIRECTIONAL
            float3 lightAtten = gi.light.color;
            #else
            float3 lightAtten = lerp( _LightColor0.rgb, gi.light.color, _Grass_TransShadow );
            #endif
            half3 lightDir = gi.light.dir + s.Normal * _TransNormalDistortion;
            half transVdotL = pow( saturate( dot( viewDir, -lightDir ) ), _TransScattering );
            half3 translucency = lightAtten * (transVdotL * _TransDirect + gi.indirect.diffuse * _Grass_TransAmbient) * s.Translucency;
            half4 c = half4( s.Albedo * translucency * _Grass_Translucency, 0 );

            SurfaceOutputStandardSpecular r;
            r.Albedo = s.Albedo;
            r.Normal = s.Normal;
            r.Emission = s.Emission;
            r.Specular = s.Specular;
            r.Smoothness = s.Smoothness;
            r.Occlusion = s.Occlusion;
            r.Alpha = s.Alpha;
            return LightingStandardSpecular (r, viewDir, gi) + c;
        }

        inline void LightingStandardSpecularCustom_GI(SurfaceOutputStandardSpecularCustom s, UnityGIInput data, inout UnityGI gi )
        {
            UNITY_GI(gi, s, data);
        }

        void surf( Input i , inout SurfaceOutputStandardSpecularCustom o )
        {
            float2 uv_MainTex = i.uv_texcoord * _MainTex_ST.xy + _MainTex_ST.zw;
            float4 tex2DNode1 = tex2D( _MainTex, uv_MainTex );
            o.Albedo = ( _Grass_Color * tex2DNode1 ).rgb;
            o.Specular = Grass_Specular_Color.rgb;
            o.Smoothness = _Grass_Smoothness;
            o.Translucency = ( tex2DNode1 * ( ( _Grass_Translucency_Intensity * _Grass_Translucency_10_x_multiplier ) * _Grass_Translucency_Color ) ).rgb;
            o.Alpha = 1;
            clip( tex2DNode1.a - _Cutoff );
        }

        ENDCG
    }
    Fallback "Diffuse"
}

Grass properties in this shader is global, so you can update settings using below way:

        Shader.SetGlobalColor ("_Grass_Color", grassColor);

Shader has been created using Amplify Shader Editor

If your terrain has grass in billboard mode, you must use below shader name:

"Hidden/TerrainEngine/Details/BillboardWavingDoublePass"

Thanks for the detailed explanation! It helps me with something else I needed to do later in the project to control grass color based on seasons

However at the moment still no change I make to the details shader seems to make a difference.

I have terrain material that uses a copied FirstPass.shader I named Nature/Terrain/Diffuse2
Inside it I have a reference to the copy of WavingDoublePass.shader that I named WavingDoublePass2:

Dependency "Details0"         = "Hidden/TerrainEngine/Details/Vertexlit"
    Dependency "Details1"         = "Hidden/TerrainEngine/Details/WavingDoublePass2"
    Dependency "Details2"         = "Hidden/TerrainEngine/Details/BillboardWavingDoublePass"

I do not use billboard for the grass.
If I comment out the dependency lines or delete everything inside WavingDoublePass2 nothing happens like I would expect to see some problem. I tried to refresh and re-add the grass brush but still nothing.

I will try this in the latest version of Unity and see if that helps

Also when I’ll manage to make any change affect it, what do you suppose makes the texture appear blurry?

You don’t need to add terrain shaders into your project
Only drag your WavingDoublePass shader into your project to have access to the grass shader

Every shader with this name (Hidden/TerrainEngine/Details/BillboardWavingDoublePass) will be replaced with the terrain default grass shader

Create your desired shader and rename it to the Hidden/TerrainEngine/Details/WavingDoublePass to use it as grass shader

Hi UnityLighting, I still had no success.
Nothing I do inside Hidden/TerrainEngine/Details/WavingDoublePass seems to affect the terrain texture.

Do you maybe have a sample project you can share where this works for you?

In the video, as you can see when i drag my own Hidden/TerrainEngine/Details/WavingDoublePass shader, the terrain details has been rendered using my detail shader