Search Unity

  1. We are looking for feedback on our SRP Rendering APIs through this Survey.
    Dismiss Notice
  2. Unity 2020.2 has been released.
    Dismiss Notice
  3. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Multitexture terrain shader

Discussion in 'Shaders' started by kilian277, Jul 30, 2014.

  1. kilian277

    kilian277

    Joined:
    Jul 13, 2012
    Posts:
    54
    Hi,

    i've maneged to get a 3 texture shader to work by fethcing the vertex colors from a model and that works.
    Now i want to add more textures to it like 6 , but you can only assign RGB to vertex colors so those are 3 textures max , now i wast hinking on using an external RGBA texture which will define the channels and textures for 3 more textures on the terrain but my problem is how to color that image i tried using a white background or black background or transparent but nothing works correctly.

    This is the shader :

    Code (CSharp):
    1. Shader "Exile/Terrain/6lyr_terrain" {
    2.     Properties
    3.     {
    4.         _Color  ("Color", Color) = (0,0,0,1)
    5.         _Layer1 ("Layer1 tex", 2D) = "white" {}
    6.         _Layer2 ("Layer2 tex", 2D) = "white" {}
    7.         _Layer3 ("Layer3 tex", 2D) = "white" {}
    8.         _Layer4 ("Layer4 tex", 2D) = "white" {}
    9.         _Layer5 ("Layer5 tex", 2D) = "white" {}
    10.         _Layer6 ("Layer6 tex", 2D) = "white" {}
    11.         _AddColorMap ("Layer 3 to 6 colormap", 2D) = "white" {}
    12.     }
    13.     SubShader
    14.     {
    15.         Pass
    16.         {
    17.             Cull Back
    18.  
    19.             Fog { Mode Off }
    20.             CGPROGRAM
    21.             // Upgrade NOTE: excluded shader from DX11 and Xbox360; has structs without semantics (struct v2f members normal)
    22.             #pragma exclude_renderers d3d11 xbox360
    23.             #include "UnityCG.cginc"
    24.             #pragma vertex vert
    25.             #pragma fragment frag
    26.             sampler2D   _Layer1;
    27.             sampler2D   _Layer2;
    28.             sampler2D   _Layer3;
    29.             sampler2D    _Layer4;
    30.             sampler2D    _AddColorMap;
    31.             float4      _Color;
    32.  
    33.             float4 _Layer1_ST;
    34.             float4 _Layer2_ST;
    35.             float4 _Layer3_ST;
    36.             float4 _Layer4_ST;
    37.             float4 _AddColorMap_ST;
    38.  
    39.             struct appdata
    40.             {
    41.                 float4 vertex : POSITION;
    42.                 float4 color : COLOR;
    43.                 float2 texcoord : TEXCOORD0;
    44.             };
    45.             struct v2f
    46.             {
    47.                 float4 pos : SV_POSITION;
    48.                 float4 color : COLOR;
    49.                 float2 uv_Layer1 : TEXCOORD0;
    50.                 float2 uv_Layer2 : TEXCOORD1;
    51.                 float2 uv_Layer3 : TEXCOORD2;
    52.                 float2 uv_Layer4 : TEXCOORD5;
    53.                 float2 uv_ADC : TEXCOORD3;
    54.                 float3 normal;
    55.                 float3 lightDir : TEXCOORD4;
    56.             };
    57.  
    58.             v2f vert (appdata_full v)
    59.             {
    60.                 v2f o;
    61.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    62.                 o.color = v.color;
    63.                 o.uv_Layer1 = TRANSFORM_TEX(v.texcoord, _Layer1);
    64.                 o.uv_Layer2 = TRANSFORM_TEX(v.texcoord, _Layer2);
    65.                 o.uv_Layer3 = TRANSFORM_TEX(v.texcoord, _Layer3);
    66.                 o.uv_Layer4 = TRANSFORM_TEX(v.texcoord, _Layer4);
    67.                 o.uv_ADC = TRANSFORM_TEX(v.texcoord, _AddColorMap);
    68.                 o.normal = normalize(mul(_Object2World,float4(v.normal,0)));
    69.                 o.lightDir = normalize(WorldSpaceLightDir(v.vertex));
    70.                 return o;
    71.             }
    72.             float4 frag (v2f i) : COLOR
    73.             {
    74.                 float4 l1 = tex2D (_Layer1, i.uv_Layer1);
    75.                 float4 l2 = tex2D (_Layer2, i.uv_Layer2);
    76.                 float4 l3 = tex2D (_Layer3, i.uv_Layer3);
    77.                 float4 l4 = tex2D (_Layer3, i.uv_Layer4);
    78.                 float4 adc = tex2D (_AddColorMap, i.uv_ADC);
    79.                 float4 color = float4(1, 1, 1, 1);
    80.                 float3 lambert = saturate (dot(i.lightDir,i.normal));
    81.  
    82.                 color.rgb = (((l1 * i.color.r) + (l2 * i.color.g) + (l3 * i.color.b)) * lambert) * _Color;
    83.                 color.rgb *=(l4 * adc.b);
    84.  
    85.                 return color;
    86.             }
    87.         ENDCG
    88.         }
    89.     }
    90. }
    Some input on how to properly achieve this problem is nice !

    Imagery on the problem:

    The external colormap :


    The problem
     
  2. mouurusai

    mouurusai

    Joined:
    Dec 2, 2011
    Posts:
    345
    If you plan draw it in some 2d application it's may become kinda ass pain. When you draw value in some layer you should subtract that value from other layers(perhaps you draw pixel in 1st texture red layer then you need subtract that value from 1.g, 1.b, 1a, 2.r, 2.g, 2.b) and in finally you need normalize all layers to 1 value (divide each layer value by their summ). In the shader only you need to do add each texture multiplied by their channel mask together. I think terrain engine works at same way.
    ------------------------
    I think little, is not necessary normalize result after 1st step, instead 2 hand drawn mask texture may be prepared to mix with this operation, but it's will be very tricky to draw good looking mask by hands.
     
    Last edited: Jul 31, 2014
  3. kilian277

    kilian277

    Joined:
    Jul 13, 2012
    Posts:
    54
    OK,

    so what do you mean exactly with the and in finally you need normalize all layers to 1 value (divide each layer value by their summ) ?.

    Because shaders is really not my strongpoint :)
     
  4. kilian277

    kilian277

    Joined:
    Jul 13, 2012
    Posts:
    54
    I have this atm , but then those divide by the sum is not really clear to me

    float3 m1red = l1 * i.color.r;
    float3 m1green = l2 * i.color.g;
    float3 m1blue = l3 * i.color.b;
    float3 m2red = l4 * adc.r;
    float3 m2green = l5 * adc.g;
    float3 m2blue = l6 * adc.b;

    float3 col1r = (m1green + m1blue + m2red + m2green + m2blue) - m1red;
    float3 col1g = (m1red + m1blue + m2red + m2green + m2blue) - m1green;
    float3 col1b = (m1red + m1green + m2red + m2green + m2blue) - m1blue;
    float3 col2r = (m1red + m1green + m1blue + m2green + m2blue) - m2red;
    float3 col2g = (m1red + m1green + m1blue + m2red + m2blue) - m2green;
    float3 col2b = (m1red + m1green + m1blue + m2red + m2green) - m2blue;

    color.rgb = ((col1r + col1g + col1b + col2r + col2g + col2b) * lambert) * _Color;
     
  5. frogsbo

    frogsbo

    Joined:
    Jan 16, 2014
    Posts:
    79
    Here is a multitexture shader. i would be grateful if you would change the crossfade values to be 6-12-16 textures. It's not very well written, it's an example of what kindof works, to write it again properly, i'd suggest shelving the crossfade values as they are done and write a new version from scratch. it's pretty good anyways:

    Code (csharp):
    1.  
    2. Shader "Custom/MultiTexture" {
    3.     Properties {
    4.         _TexTop ("Top", 2D) = "white" {}
    5.         _TexMid ("Mid", 2D) = "white" {}
    6.         _TexBot ("Bot", 2D) = "white" {}
    7.         _TopLimit("TopLimit", Range(-1, 1)) = 0.7
    8.         _BotLimit("BotLimit", Range(-1, 1)) = 0.27
    9.         _MidLimit("MidLimit", Range(-1, 1)) = 0.43
    10.         _TotalMetres("TotalMetres", float) = 100
    11.         _MidZone("_MidZone", Range(-100, 100)) = 20
    12.     }
    13.     SubShader {
    14.         Tags { "RenderType"="Opaque" }
    15.         LOD 200
    16.         //Cull Off
    17.        
    18.         CGPROGRAM
    19.         #pragma surface surf Lambert
    20.         #pragma exclude_renderers ps3 flash
    21.        
    22.        
    23.         sampler2D _TexTop;
    24.         sampler2D _TexMid;
    25.         sampler2D _TexBot;
    26.        
    27.         float _TopLimit;
    28.         float _MidLimit;
    29.         float _BotLimit;
    30.         float _TotalMetres,_MidZone;
    31.         struct Input {
    32.             float2 uv_TexTop;
    33.             float3 worldNormal;
    34.             float incline;
    35.             float3 worldPos;
    36.         };
    37.         void vert (inout appdata_full v, out Input o) {
    38.           UNITY_INITIALIZE_OUTPUT(Input,o);
    39.           o.incline = abs(v.normal.y);
    40.         }
    41.  
    42.         void surf (Input IN, inout SurfaceOutput o) {      
    43.             float Alti = (IN.worldPos.y+_MidZone)/_TotalMetres;
    44.                
    45.             float4 resultCol =
    46.             // Above topLimit, 100% topTexture
    47.                Alti >= _TopLimit ? tex2D(_TexTop, IN.uv_TexTop)
    48.             // Below botLimit, 100% botTexture
    49.             : (Alti <= -_BotLimit ? tex2D(_TexBot, IN.uv_TexTop)
    50.             // Between sideLimit and -MidLimit, 100% MidTexture
    51.             : (Alti <= _MidLimit && Alti >= -_MidLimit ? tex2D(_TexMid, IN.uv_TexTop)
    52.             // Above 0 outside thresholds, blend between side and top
    53.             : (Alti > 0 ? lerp(tex2D(_TexTop, IN.uv_TexTop), tex2D(_TexMid, IN.uv_TexTop),
    54.                                  1 - ((Alti - _MidLimit) / (_TopLimit - _MidLimit)))
    55.             // Below 0, outside thresholds, blend between side and bot
    56.             : lerp(tex2D(_TexBot, IN.uv_TexTop), tex2D(_TexMid, IN.uv_TexTop),
    57.                 1 - ((abs(Alti) - _MidLimit) / (abs(_BotLimit) - _MidLimit))))));
    58.                
    59.             o.Albedo = resultCol.rgb;
    60.             o.Alpha = resultCol.a;
    61.         }
    62.         ENDCG
    63.     }
    64.     FallBack "Diffuse"
    65. }
    66.  
    67.  
     
  6. kilian277

    kilian277

    Joined:
    Jul 13, 2012
    Posts:
    54
    First of all thanks for the reply but i should have mentioned that i fixed my problem and fully wrote a correctly working shader with 5 textures blending at the same time (had to disable one channel on the second mask to allow for the previous textures to only be drawn by that single mask so it wouldn't draw under the two other textures of the second mask texture :)
     
  7. frogsbo

    frogsbo

    Joined:
    Jan 16, 2014
    Posts:
    79
    it's technically referred to as a splatmap btw :)
     
unityunity