Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Setting o.normal is making my shader do weird things

Discussion in 'Shaders' started by 4ringz, Dec 10, 2016.

  1. 4ringz

    4ringz

    Joined:
    Apr 22, 2015
    Posts:
    13
    Very new to shaders so I apologize if I'm making a basic error in this.

    I'm experimenting with making my own shader for procedural terrain meshes. I have it working right now as a diffuse-only shader that blends four different textures based on height and another based on slope (world normal).

    I added code to do normal map blending as well, but weird stuff happens when I set o.normal. If I comment out that one line at the end and leave everything else as is, it functions perfectly.

    The noted weirdnesses are 1) That certain diffuse textures are still there but others are "whited out" entirely; 2) that the diffuse blending breaks; and 3) the normal maps look weird anyway.

    I appreciate any pointing in the right direction as I don't really know how to debug this and can't find any other shaders with similar errors. Thanks!

    Shader follows:

    Code (CSharp):
    1. Shader "Custom/Terrain" {
    2.     Properties{
    3.         //Diffuse maps
    4.         _Elevation1Tex("Elevation 1 Diffuse", 2D) = "white" {}
    5.         _Elevation2Tex("Elevation 2 Diffuse", 2D) = "white" {}
    6.         _Elevation3Tex("Elevation 3 Diffuse", 2D) = "white" {}
    7.         _Elevation4Tex("Elevation 4 Diffuse", 2D) = "white" {}
    8.         _SlopeTex("Slope Diffuse", 2D) = "white" {}
    9.  
    10.         //Normal Maps
    11.         _Elevation1Normal("Elevation 1 Normal", 2D) = "bump" {}
    12.         _Elevation2Normal("Elevation 2 Normal", 2D) = "bump" {}
    13.         _Elevation3Normal("Elevation 3 Normal", 2D) = "bump" {}
    14.         _Elevation4Normal("Elevation 4 Normal", 2D) = "bump" {}
    15.         _SlopeNormal("Slope Normal", 2D) = "bump" {}
    16.  
    17.         //For slope calculations.
    18.         _VertDir("Vertical Direction", Vector) = (0.0, 1.0, 0.0)
    19.         _SlopeIntensity("Slope Intensity", Range(0.1, 5.0)) = 2.0
    20.         _MinSlope("Minimum Slope Attenuation", Range(0.0, 2.0)) = 0.1
    21.  
    22.         //Need one of each threshold + radius for (elevation maps)-1
    23.         _Elev1Level("Elevation 1 Height Threshold", Range(0.0, 1.0)) = 0.1
    24.         _Elev1Fade("Elevation 1 Attenuation Radius",Range(0.0,0.2)) = 0.05
    25.         _Elev2Level("Elevation 2 Height Threshold", Range(0.0, 1.0)) = 0.2
    26.         _TempTest("Elevation 2 Attenuation Radius",Range(0.0,0.2)) = 0.05
    27.         _Elev3Level("Elevation 3 Height Threshold", Range(0.0, 1.0)) = 0.3
    28.         _Elev3Fade("Elevation 3 Attenuation Radius",Range(0.0,0.2))= 0.05
    29.  
    30.     }
    31.     SubShader{
    32.         Tags { "RenderType" = "Opaque" }
    33.         LOD 200
    34.         CGPROGRAM
    35.         // Physically based Standard lighting model, and enable shadows on all light types
    36.         #pragma surface surf Standard fullforwardshadows
    37.         //#pragma surface surf Lambert
    38.         // Use shader model 3.0 target, to get nicer looking lighting
    39.         #pragma target 4.0
    40.  
    41.         sampler2D _Elevation1Tex;
    42.         sampler2D _Elevation2Tex;
    43.         sampler2D _Elevation3Tex;
    44.         sampler2D _Elevation4Tex;
    45.         sampler2D _SlopeTex;
    46.  
    47.         sampler2D _Elevation1Normal;
    48.         sampler2D _Elevation2Normal;
    49.         sampler2D _Elevation3Normal;
    50.         sampler2D _Elevation4Normal;
    51.         sampler2D _SlopeNormal;
    52.  
    53.         float4 _VertDir;
    54.         float _SlopeIntensity;
    55.  
    56.         float _Elev1Level;
    57.         float _Elev2Level;
    58.         float _Elev3Level;
    59.         float _Elev1Fade;
    60.         float _TempTest;
    61.         float _Elev3Fade;
    62.         float _MinSlope; //Attenuate the slope fade-in factor from here (IE underwater to beaches we may not want cliff appearance)
    63.  
    64.         float minHeight;
    65.         float maxHeight;
    66.  
    67.         struct Input {
    68.             float3 worldPos;
    69.             float3 worldNormal; INTERNAL_DATA //Need INTERNAL_DATA to pull normal vector since our shader writes to o.Normal
    70.             float2 uv_Elevation1Tex;
    71.             float2 uv_Elevation2Tex;
    72.             float2 uv_Elevation3Tex;
    73.             float2 uv_Elevation4Tex;
    74.             float2 uv_SlopeTex;
    75.             float2 uv_Elevation1Normal;
    76.             float2 uv_Elevation2Normal;
    77.             float2 uv_Elevation3Normal;
    78.             float2 uv_Elevation4Normal;
    79.             float2 uv_SlopeNormal;
    80.         };
    81.  
    82.         float inverseLerp(float a, float b, float value) {
    83.             return saturate((value - a) / (b - a));
    84.         }
    85.  
    86.         void surf(Input IN, inout SurfaceOutputStandard o) {
    87.  
    88.             float heightPercent = inverseLerp(minHeight, maxHeight, IN.worldPos.y);
    89.  
    90.             fixed4 elev1Tex = tex2D(_Elevation1Tex, IN.uv_Elevation1Tex);
    91.             fixed4 elev2Tex = tex2D(_Elevation2Tex, IN.uv_Elevation2Tex);
    92.             fixed4 elev3Tex = tex2D(_Elevation3Tex, IN.uv_Elevation3Tex);
    93.             fixed4 elev4Tex = tex2D(_Elevation4Tex, IN.uv_Elevation4Tex);
    94.             fixed4 slopeTex = tex2D(_SlopeTex, IN.uv_SlopeTex);
    95.  
    96.             fixed4 elev1Normal = tex2D(_Elevation1Normal, IN.uv_Elevation1Normal);
    97.             fixed4 elev2Normal = tex2D(_Elevation2Normal, IN.uv_Elevation2Normal);
    98.             fixed4 elev3Normal = tex2D(_Elevation3Normal, IN.uv_Elevation3Normal);
    99.             fixed4 elev4Normal = tex2D(_Elevation4Normal, IN.uv_Elevation4Normal);
    100.             fixed4 slopeNormal = tex2D(_SlopeNormal, IN.uv_SlopeNormal);
    101.  
    102.             //Default to highest
    103.             fixed4 diffuseOut = elev4Tex;
    104.             fixed4 normalOut = elev4Normal;
    105.  
    106.             if (heightPercent < (_Elev1Level + _Elev1Fade)) {
    107.                 if (heightPercent < (_Elev1Level - _Elev1Fade)) {
    108.                     diffuseOut = elev1Tex; //Pure texture 1
    109.                     normalOut = elev1Normal;
    110.                 }
    111.                 else {
    112.                     diffuseOut = lerp(elev1Tex, elev2Tex, inverseLerp(_Elev1Level - _Elev1Fade, _Elev1Level + _Elev1Fade, heightPercent));
    113.                     normalOut = lerp(elev1Normal, elev2Normal, inverseLerp(_Elev1Level - _Elev1Fade, _Elev1Level + _Elev1Fade, heightPercent));
    114.                 }
    115.             }
    116.             else {
    117.  
    118.                 if (heightPercent < (_Elev2Level + _TempTest)) {
    119.                     if (heightPercent < (_Elev2Level - _TempTest)) {
    120.                         diffuseOut = elev2Tex; //Pure texture 2
    121.                         normalOut = elev2Normal;
    122.                     }
    123.                     else {
    124.                         diffuseOut = lerp(elev2Tex, elev3Tex,inverseLerp(_Elev2Level - _TempTest, _Elev2Level + _TempTest, heightPercent));
    125.                         normalOut = lerp(elev2Normal, elev3Normal, inverseLerp(_Elev1Level - _Elev1Fade, _Elev1Level + _Elev1Fade, heightPercent));
    126.                     }
    127.                 }
    128.                 else {
    129.  
    130.                     if (heightPercent < (_Elev3Level + _Elev3Fade)) {
    131.                         if (heightPercent < (_Elev3Level - _Elev3Fade)) {
    132.                             diffuseOut = elev3Tex; //Pure texture 3
    133.                             normalOut = elev3Normal;
    134.                         }
    135.                         else {
    136.                             diffuseOut = lerp(elev3Tex, elev4Tex, inverseLerp(_Elev3Level - _Elev3Fade, _Elev3Level + _Elev3Fade, heightPercent));
    137.                             normalOut = lerp(elev3Normal, elev4Normal, inverseLerp(_Elev1Level - _Elev1Fade, _Elev1Level + _Elev1Fade, heightPercent));
    138.                         }
    139.                     }
    140.                     else {
    141.                         diffuseOut = elev4Tex;
    142.                         normalOut = elev4Normal;
    143.                     }
    144.                 }
    145.             }
    146.  
    147.             //Mix in the slope calculations
    148.             float slope = 1-dot(normalize(IN.worldNormal), _VertDir.xyz);
    149.             if (slope < 0) slope = 0;
    150.             slope = slope * _SlopeIntensity;
    151.             if (heightPercent < _MinSlope) {
    152.                 if (heightPercent < _MinSlope - 0.1) {         //For now hardcoded - 0.1 from start of attenuation, we lose slope blend effect
    153.                     slope = 0;
    154.                 }
    155.                 else {
    156.                     slope = slope * inverseLerp(_MinSlope - 0.1,_MinSlope,heightPercent);
    157.                 }
    158.             }
    159.             else {
    160.             }
    161.  
    162.             diffuseOut = lerp(diffuseOut, slopeTex, slope);
    163.             normalOut = lerp(normalOut, slopeNormal, slope);
    164.  
    165.             o.Albedo = diffuseOut.rgb;
    166.             //o.Normal = UnpackNormal(normalOut);
    167.  
    168.             //Using normals is 'whiting out' some other textures and doesn't look very good,
    169.             //so disable until we figure out the issue
    170.  
    171.         }
    172.         ENDCG
    173.     }
    174.     FallBack "Diffuse"
    175. }
    working.png weird.png shadersettings.png
     
  2. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    You can do height blends without ifs, that's going to kill your performance as is.

    What do you get if you don't use unpack normal and just do "o.Normal = normalOut*2 -1" ?
     
  3. 4ringz

    4ringz

    Joined:
    Apr 22, 2015
    Posts:
    13
    I'll give it a shot. Are the ifs more expensive than the blending? I hadn't even considered that. (Again, VERY new to shaders.) Will update when I give it a try - thank you.
     
  4. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    Typically the GPU will render all branches then evaluate the correct result and display that one pixel, so you'd be rendering the same pixel more than once. Until you're really sure what you're doing its better to avoid branches.

    Height blending textures for terrain is pretty common, you can find examples if you google around that will give you nice results.