Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Terrain bump mapped + detail texture for 1 splat (Caustics)

Discussion in 'Made With Unity' started by aubergine, Dec 29, 2010.

  1. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878


    Using the base shader found here:
    http://forum.unity3d.com/threads/63282-Bump-maps-for-built-in-terrain

    below is the replacement shader:
    Code (csharp):
    1. /* Code provided by Chris Morris of Six Times Nothing (http://www.sixtimesnothing.com) */
    2. /* Free to use and modify  */
    3. /* Edited by Aubergine (3 lines :p) */
    4.  
    5.  
    6. Shader "Hidden/TerrainEngine/Splatmap/Lightmap-FirstPass" {
    7. Properties {
    8.     _Control ("Control (RGBA)", 2D) = "red" {}
    9.     _Splat3 ("Layer 3 (A)", 2D) = "white" {}
    10.     _Splat2 ("Layer 2 (B)", 2D) = "white" {}
    11.     _Splat1 ("Layer 1 (G)", 2D) = "white" {}
    12.     _Splat0 ("Layer 0 (R)", 2D) = "white" {}
    13.     // used in fallback on old cards
    14.     _MainTex ("BaseMap (RGB)", 2D) = "white" {}
    15.     _Color ("Main Color", Color) = (1,1,1,1)
    16.    
    17.     _SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
    18. }
    19.  
    20. SubShader {
    21.     Tags {
    22.         "SplatCount" = "4"
    23.         "Queue" = "Geometry-100"
    24.         "RenderType" = "Opaque"
    25.     }
    26. CGPROGRAM
    27. #pragma surface surf BlinnPhong vertex:vert
    28. #pragma target 3.0
    29. #include "UnityCG.cginc"
    30.  
    31. struct Input {
    32.     float3 worldPos;
    33.     float2 uv_BumpMap;
    34.     float2 uv_Control : TEXCOORD0;
    35.     float2 uv_Splat0 : TEXCOORD1;
    36.     float2 uv_Splat1 : TEXCOORD2;
    37.     float2 uv_Splat2 : TEXCOORD3;
    38.     float2 uv_Splat3 : TEXCOORD4;
    39. };
    40.  
    41. // Supply the shader with tangents for the terrain
    42. void vert (inout appdata_full v) {
    43.  
    44.     // A general tangent estimation
    45.     float3 T1 = float3(1, 0, 1);
    46.     float3 Bi = cross(T1, v.normal);
    47.     float3 newTangent = cross(v.normal, Bi);
    48.    
    49.     normalize(newTangent);
    50.  
    51.     v.tangent.xyz = newTangent.xyz;
    52.    
    53.     if (dot(cross(v.normal,newTangent),Bi) < 0)
    54.         v.tangent.w = -1.0f;
    55.     else
    56.         v.tangent.w = 1.0f;
    57. }
    58.  
    59. sampler2D _Control;
    60. sampler2D _BumpMap0, _BumpMap1, _BumpMap2, _BumpMap3;
    61. sampler2D _Splat0,_Splat1,_Splat2,_Splat3;
    62.  
    63. sampler2D _DetailTX;
    64.  
    65. float _Spec0, _Spec1, _Spec2, _Spec3, _Tile0, _Tile1, _Tile2, _Tile3, _TerrainX, _TerrainZ;
    66. float4 _v4CameraPos;
    67.  
    68. void surf (Input IN, inout SurfaceOutput o) {
    69.  
    70.     half4 splat_control = tex2D (_Control, IN.uv_Control);
    71.     half3 col;
    72.     half3 detail;
    73.    
    74.     // 4 splats, normals, and specular settings
    75.     col  = splat_control.r * tex2D (_Splat0, IN.uv_Splat0).rgb;
    76.     o.Normal = splat_control.r * UnpackNormal(tex2D(_BumpMap0, float2(IN.uv_BumpMap.x * (_TerrainX/_Tile0), IN.uv_BumpMap.y * (_TerrainZ/_Tile0))));
    77.     o.Gloss = _Spec0 * splat_control.r;
    78.     o.Specular = _Spec0 * splat_control.r;
    79.  
    80.     col += splat_control.g * tex2D (_Splat1, IN.uv_Splat1).rgb;
    81.     o.Normal += splat_control.g * UnpackNormal(tex2D(_BumpMap1, float2(IN.uv_BumpMap.x * (_TerrainX/_Tile1), IN.uv_BumpMap.y * (_TerrainZ/_Tile1))));
    82.     o.Gloss += _Spec1 * splat_control.g;
    83.     o.Specular += _Spec1 * splat_control.g;
    84.    
    85.     col += splat_control.b * tex2D (_Splat2, IN.uv_Splat2).rgb;
    86.     o.Normal += splat_control.b * UnpackNormal(tex2D(_BumpMap2, float2(IN.uv_BumpMap.x * (_TerrainX/_Tile2), IN.uv_BumpMap.y * (_TerrainZ/_Tile2))));
    87.     o.Gloss += _Spec2 * splat_control.b;
    88.     o.Specular +=_Spec2 * splat_control.b;
    89.    
    90.     col += splat_control.a * (tex2D (_Splat3, IN.uv_Splat3).rgb + tex2D (_DetailTX, IN.uv_Splat3).rgb);
    91.     o.Normal += splat_control.a * UnpackNormal(tex2D(_BumpMap3, float2(IN.uv_BumpMap.x * (_TerrainX/_Tile3), IN.uv_BumpMap.y * (_TerrainZ/_Tile3))));
    92.     o.Gloss += _Spec3 * splat_control.a;
    93.     o.Specular += _Spec3 * splat_control.a;
    94.    
    95.     o.Albedo = col;
    96.     o.Alpha = 0.0;
    97. }
    98. ENDCG  
    99. }
    100.  
    101. // Fallback to Diffuse
    102. Fallback "Diffuse"
    103. }
    aand below is the script to attach to the terrain:
    Code (csharp):
    1. /* Code provided by Chris Morris of Six Times Nothing (http://www.sixtimesnothing.com) */
    2. /* Free to use and modify */
    3. /* Edited by Aubergine (more than 3 lines of code:p)*/
    4.  
    5. using UnityEngine;
    6. using System.Collections;
    7.  
    8. [AddComponentMenu ("Frameworks/Terrain/TerrainNormalMap")]
    9. public class TerrainNormalMap : MonoBehaviour {
    10.  
    11.     public Texture2D Bump0;
    12.     public Texture2D Bump1;
    13.     public Texture2D Bump2;
    14.     public Texture2D Bump3;
    15.    
    16.     public Texture2D[] DetailTXArray;
    17.     private Texture2D DetailTX;
    18.     private float img = 0.0F;
    19.     private bool canDetail;
    20.     private float detailFPS = 15.0F;
    21.    
    22.     public float Tile0;
    23.     public float Tile1;
    24.     public float Tile2;
    25.     public float Tile3;
    26.  
    27.     public float Spec0;
    28.     public float Spec1;
    29.     public float Spec2;
    30.     public float Spec3;
    31.    
    32.     public float terrainSizeX;
    33.     public float terrainSizeZ;
    34.    
    35.     void Start () {
    36.        
    37.         Terrain terrainComp = (Terrain)GetComponent(typeof(Terrain));
    38.        
    39.         if(Bump0)
    40.             Shader.SetGlobalTexture("_BumpMap0", Bump0);
    41.        
    42.         if(Bump1)
    43.             Shader.SetGlobalTexture("_BumpMap1", Bump1);
    44.        
    45.         if(Bump2)
    46.             Shader.SetGlobalTexture("_BumpMap2", Bump2);
    47.        
    48.         if(Bump3)
    49.             Shader.SetGlobalTexture("_BumpMap3", Bump3);
    50.        
    51.         if(DetailTXArray.Length > 0) {
    52.             canDetail = true;
    53.             DetailTX = DetailTXArray[0];
    54.             Shader.SetGlobalTexture("_DetailTX", DetailTX);
    55.         }
    56.         Shader.SetGlobalFloat("_Spec0", Spec0);
    57.         Shader.SetGlobalFloat("_Spec1", Spec1);
    58.         Shader.SetGlobalFloat("_Spec2", Spec2);
    59.         Shader.SetGlobalFloat("_Spec3", Spec3);
    60.  
    61.         Shader.SetGlobalFloat("_Tile0", Tile0);
    62.         Shader.SetGlobalFloat("_Tile1", Tile1);
    63.         Shader.SetGlobalFloat("_Tile2", Tile2);
    64.         Shader.SetGlobalFloat("_Tile3", Tile3);
    65.        
    66.         terrainSizeX = terrainComp.terrainData.size.x;
    67.         terrainSizeZ = terrainComp.terrainData.size.z;
    68.        
    69.         Shader.SetGlobalFloat("_TerrainX", terrainSizeX);
    70.         Shader.SetGlobalFloat("_TerrainZ", terrainSizeZ);
    71.     }
    72.    
    73.     /* Don't need this update unless you're testing during play */
    74.     void Update () {
    75.        
    76.         if(Bump0)
    77.             Shader.SetGlobalTexture("_BumpMap0", Bump0);
    78.        
    79.         if(Bump1)
    80.             Shader.SetGlobalTexture("_BumpMap1", Bump1);
    81.        
    82.         if(Bump2)
    83.             Shader.SetGlobalTexture("_BumpMap2", Bump2);
    84.        
    85.         if(Bump3)
    86.             Shader.SetGlobalTexture("_BumpMap3", Bump3);
    87.  
    88.         if(canDetail) {
    89.             float i = Time.time * detailFPS;
    90.             i = i % DetailTXArray.Length;
    91.             DetailTX = DetailTXArray[(int)i];
    92.             Shader.SetGlobalTexture("_DetailTX", DetailTX);
    93.         }
    94.        
    95.         Shader.SetGlobalFloat("_Spec0", Spec0);
    96.         Shader.SetGlobalFloat("_Spec1", Spec1);
    97.         Shader.SetGlobalFloat("_Spec2", Spec2);
    98.         Shader.SetGlobalFloat("_Spec3", Spec3);
    99.  
    100.         Shader.SetGlobalFloat("_Tile0", Tile0);
    101.         Shader.SetGlobalFloat("_Tile1", Tile1);
    102.         Shader.SetGlobalFloat("_Tile2", Tile2);
    103.         Shader.SetGlobalFloat("_Tile3", Tile3);
    104.        
    105.         Shader.SetGlobalFloat("_TerrainX", terrainSizeX);
    106.         Shader.SetGlobalFloat("_TerrainZ", terrainSizeZ);
    107.     }
    108. }
    How to use:
    There is a free caustics generator software (search google), using this one export an animated series of textures
    Just normap map and do every other thing mentioned in the first link (which is the main base of this shader)
    Attach your caustics to the array and you will see the 4th splat is now blending with main texture, normal texture and this detail caustics.

    Code may look messy, but sure you can tidy it yourself.
    It looks better when animated :)
     

    Attached Files:

    Last edited: Dec 29, 2010
  2. handsomePATT

    handsomePATT

    Joined:
    Nov 30, 2010
    Posts:
    574
    could you show me what it looks like when playing. I cant get mine to look very good
     
  3. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    Im at work now, ill pack a small web player for you tonight.
     
  4. handsomePATT

    handsomePATT

    Joined:
    Nov 30, 2010
    Posts:
    574
    thanks alot man
     
  5. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    You can find the simple web player here to see how it looks like in realtime.
    i tried to attach it to this post but it didnt work.
     
  6. bigkahuna

    bigkahuna

    Joined:
    Apr 30, 2006
    Posts:
    5,434
    That is pretty cool. Nice work!
     
  7. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    You know it can be used for anything like lava, caustics or anything you want detail mapped.
     
  8. RoyS

    RoyS

    Joined:
    Jan 12, 2009
    Posts:
    664
    I never thought about lava. Perfect for that. Thanks Aubergine.
     
  9. elias_t

    elias_t

    Joined:
    Sep 17, 2010
    Posts:
    1,367
    Excellent!
    I will try to modify it to enhance seashore waves.
     
  10. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    You can do it with an additional alpha map for the 4th splat uvs and multiply the detail with this alpha map. But why bother, you will be using an extra texture anyhow soo, just use the 4th texture as your seashore and another texture for the deep parts.
     
  11. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    Below versions are slightly better and easier to use.

    Shader:
    Code (csharp):
    1. Shader "Hidden/TerrainEngine/Splatmap/Lightmap-FirstPass" {
    2. Properties {
    3.     _Control ("Control (RGBA)", 2D) = "red" {}
    4.     _Splat3 ("Layer 3 (A)", 2D) = "white" {}
    5.     _Splat2 ("Layer 2 (B)", 2D) = "white" {}
    6.     _Splat1 ("Layer 1 (G)", 2D) = "white" {}
    7.     _Splat0 ("Layer 0 (R)", 2D) = "white" {}
    8.     // used in fallback on old cards
    9.     _MainTex ("BaseMap (RGB)", 2D) = "white" {}
    10.     _Color ("Main Color", Color) = (1,1,1,1)
    11.    
    12.     _SpecColor ("Specular Color", Color) = (1.0, 0.5, 0.5, 1)
    13. }
    14.    
    15. SubShader {
    16.     Tags {
    17.         "SplatCount" = "4"
    18.         "Queue" = "Geometry-100"
    19.         "RenderType" = "Opaque"
    20.     }
    21. CGPROGRAM
    22. #pragma surface surf BlinnPhong vertex:vert
    23. #pragma target 3.0
    24.  
    25. struct Input {
    26.     float2 uv_BumpMap;
    27.     float2 uv_Control : TEXCOORD0;
    28.     float2 uv_Splat0 : TEXCOORD1;
    29.     float2 uv_Splat1 : TEXCOORD2;
    30.     float2 uv_Splat2 : TEXCOORD3;
    31.     float2 uv_Splat3 : TEXCOORD4;
    32. };
    33.  
    34. void vert (inout appdata_full v) {
    35.     float3 T1 = float3(1, 0, 1);
    36.     float3 Bi = cross(T1, v.normal);
    37.     float3 newTangent = cross(v.normal, Bi);
    38.     normalize(newTangent);
    39.     v.tangent.xyz = newTangent.xyz;
    40.     if (dot(cross(v.normal,newTangent),Bi) < 0)
    41.         v.tangent.w = -1.0f;
    42.     else
    43.         v.tangent.w = 1.0f;
    44. }
    45.  
    46. sampler2D _Control;
    47. sampler2D _Splat0, _Splat1, _Splat2, _Splat3;
    48. sampler2D _Bump00, _Bump01, _Bump02, _Bump03;
    49. sampler2D _DetailMap;
    50.  
    51. float _SpecPow00, _SpecPow01, _SpecPow02, _SpecPow03;
    52. float _TileX00, _TileX01, _TileX02, _TileX03, _TileZ00, _TileZ01, _TileZ02, _TileZ03;
    53. float _TerX, _TerZ;
    54. half4 _SpecCol;
    55.  
    56. void surf (Input IN, inout SurfaceOutput o) {
    57.     half4 splat_control = tex2D (_Control, IN.uv_Control);
    58.     half3 col;
    59.     _SpecColor = _SpecCol;
    60.    
    61.     col  = splat_control.r * tex2D (_Splat0, IN.uv_Splat0).rgb;
    62.     o.Normal = splat_control.r * UnpackNormal (tex2D (_Bump00, float2(IN.uv_Control.x * (_TerX/_TileX00), IN.uv_Control.y * (_TerZ/_TileZ00))));
    63.     o.Gloss = _SpecPow00 * splat_control.r;
    64.     o.Specular = _SpecPow00 * splat_control.r;
    65.    
    66.     col += splat_control.g * tex2D (_Splat1, IN.uv_Splat1).rgb;
    67.     o.Normal += splat_control.g * UnpackNormal (tex2D (_Bump01, float2(IN.uv_Control.x * (_TerX/_TileX01), IN.uv_Control.y * (_TerZ/_TileZ01))));
    68.     o.Gloss += _SpecPow01 * splat_control.g;
    69.     o.Specular += _SpecPow01 * splat_control.g;
    70.    
    71.     col += splat_control.b * tex2D (_Splat2, IN.uv_Splat2).rgb;
    72.     o.Normal += splat_control.b * UnpackNormal (tex2D (_Bump02, float2(IN.uv_Control.x * (_TerX/_TileX02), IN.uv_Control.y * (_TerZ/_TileZ02))));
    73.     o.Gloss += _SpecPow02 * splat_control.b;
    74.     o.Specular += _SpecPow02 * splat_control.b;
    75.    
    76.     col += splat_control.a * tex2D (_Splat3, IN.uv_Splat3).rgb;
    77.     col += splat_control.a * tex2D (_DetailMap, IN.uv_Splat3).rgb;
    78.     o.Normal += splat_control.a * UnpackNormal (tex2D (_Bump03, float2(IN.uv_Control.x * (_TerX/_TileX03), IN.uv_Control.y * (_TerZ/_TileZ03))));
    79.     o.Gloss += _SpecPow03 * splat_control.a;
    80.     o.Specular += _SpecPow03 * splat_control.a;
    81.     o.Albedo = col;
    82.     o.Alpha = 0.0;
    83. }
    84. ENDCG  
    85. }
    86.  
    87. // Fallback to Diffuse
    88. Fallback "Diffuse"
    89. }
    Script:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Terrain_Bump : MonoBehaviour {
    5.    
    6.     public Texture2D[] bumpMaps;
    7.     public float[] specularPowers;
    8.     public Color specularColor = Color.grey;
    9.     public Texture2D[] detailMaps;
    10.     public float detailFPS = 15.0F;
    11.    
    12.     void Awake () {
    13.         Terrain terrain = (Terrain)GetComponent(typeof(Terrain));
    14.         int splatCount = terrain.terrainData.alphamapLayers;
    15.        
    16.         float[] tileSizeX = new float[splatCount];
    17.         float[] tileSizeZ = new float[splatCount];
    18.         for (int i = 0; i < splatCount; i++) {
    19.             tileSizeX[i] = terrain.terrainData.splatPrototypes[i].tileSize.x;
    20.             tileSizeZ[i] = terrain.terrainData.splatPrototypes[i].tileSize.y;
    21.             string tileX = "_TileX0"+i.ToString();
    22.             string tileZ = "_TileZ0"+i.ToString();
    23.             Shader.SetGlobalFloat (tileX, tileSizeX[i]);
    24.             Shader.SetGlobalFloat (tileZ, tileSizeZ[i]);
    25.         }
    26.        
    27.         for (int i = 0; i < bumpMaps.Length; i++) {
    28.             if (bumpMaps[i] != null) {
    29.                 string bump = "_Bump0"+i.ToString();
    30.                 Shader.SetGlobalTexture(bump, bumpMaps[i]);
    31.             }
    32.         }
    33.        
    34.         for (int i = 0; i < specularPowers.Length; i++) {
    35.             string spec = "_SpecPow0"+i.ToString();
    36.             Shader.SetGlobalFloat(spec, specularPowers[i]);
    37.         }
    38.         Shader.SetGlobalColor("_SpecCol", specularColor);
    39.         Shader.SetGlobalFloat("_TerX", terrain.terrainData.size.x);
    40.         Shader.SetGlobalFloat("_TerZ", terrain.terrainData.size.z);
    41.     }
    42.  
    43.     void Update () {
    44.         float i = Time.time * detailFPS;
    45.         i = i % detailMaps.Length;
    46.         //DetailTX = detailMaps[(int)i];
    47.         Shader.SetGlobalTexture("_DetailMap", detailMaps[(int)i]);
    48.     }
    49. }
     
  12. 3dDude

    3dDude

    Joined:
    Jul 4, 2010
    Posts:
    1,067
    Could you maybe post a package? looks really cool but I have a mac and non of those apps work for me :(
     
  13. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
  14. seanmars

    seanmars

    Joined:
    Jun 7, 2011
    Posts:
    14