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. Dismiss Notice

Texture Terrain using Slope Angles

Discussion in 'Scripting' started by AlucardJay, Nov 9, 2013.

  1. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    Terrain Toolkit has an excellent function for texturing a terrain based on setting heights where they exist and also blend between.

    I have been unsuccessfully trying to convert this so that it textures a terrain based on the slope angle.

    Is anyone interested in helping out to get this to work?

    I have included an edited working version of both methods, my uJS converted method of texturing by heights from Terrain Toolkit, and my attempt for converting this to use the slope angle data rather than the heightmap data.

    Code (csharp):
    1.  
    2. //------------------------------//
    3. //  TerrainAlphamaps.js         //
    4. //  Written by Alucard Jay      //
    5. //  11/10/2013                  //
    6. //------------------------------//
    7.  
    8. //  based on Terrain Toolkit ( TerrainToolkit.cs ) by sixtimesnothing
    9.  
    10.  
    11. #pragma strict
    12.  
    13.  
    14. #if UNITY_EDITOR
    15.  
    16. @ContextMenu( "Generate AlphaMap" )
    17.  
    18. function GenerateAlphaMap()
    19. {
    20.     Start();
    21. }
    22.  
    23. #endif
    24.  
    25.  
    26. //  Script Management
    27. //  ----------------------------------------------------------------------------
    28.  
    29.  
    30. enum TextureMethod
    31. {
    32.     UsingHeights,
    33.     UsingSlopeAngles
    34. }
    35.  
    36. public var textureBy : TextureMethod;
    37.  
    38.  
    39. function Start()
    40. {
    41.     // Load or find the terrain and get Terrain Data
    42.     GetTerrainData();
    43.    
    44.     // Texture the Terrain
    45.     switch ( textureBy )
    46.     {
    47.         case TextureMethod.UsingHeights :
    48.             TextureTerrainUsingHeights();
    49.         break;
    50.        
    51.         case TextureMethod.UsingSlopeAngles :
    52.             TextureTerrainUsingSlopeAngles();
    53.         break;
    54.     }
    55. }
    56.  
    57.  
    58. function Update()
    59. {
    60.     if ( Input.GetMouseButtonDown(0) )
    61.     {
    62.         Start();
    63.     }
    64. }
    65.  
    66.  
    67. //  Terrain Data
    68. //  ----------------------------------------------------------------------------
    69.  
    70.  
    71. public var terrain : Terrain;
    72. private var terrainData : TerrainData;
    73.  
    74. private var heightmapWidth : int;
    75. private var heightmapHeight : int;
    76.  
    77.  
    78. function GetTerrainData()
    79. {
    80.     if ( !terrain )
    81.     {
    82.         terrain = Terrain.activeTerrain;
    83.     }
    84.    
    85.     terrainData = terrain.terrainData;
    86.    
    87.     heightmapWidth = terrain.terrainData.heightmapWidth;
    88.     heightmapHeight = terrain.terrainData.heightmapHeight;
    89. }
    90.  
    91.  
    92. //  ============================================================================
    93.  
    94.  
    95. //  ============================================================================
    96. //  
    97. //  
    98. //  below is written based from sixtimesnothing Terrain Toolkit ( TerrainToolkit.cs )
    99. //  
    100. //  http://www.sixtimesnothing.com/terraintoolkit
    101. //  
    102. //  http://sixtimesnothing.wordpress.com/
    103. //  
    104. //  http://code.google.com/p/unityterraintoolkit/
    105. //  
    106. //
    107. //  ============================================================================
    108.  
    109.  
    110. //  Terrain Texturing
    111. //  ----------------------------------------------------------------------------
    112.  
    113.  
    114. // -- Original using Heights --
    115.  
    116.  
    117. private var splatPrototypes : SplatPrototype[];
    118.  
    119. public var slopeBlendMinAngle : float = 32.0;
    120. public var slopeBlendMaxAngle : float = 48.0;
    121.  
    122. public var heightBlendPoints : float[];
    123.  
    124.  
    125. function TextureTerrainUsingHeights()
    126. {
    127.     // store a reference to the terrain textures
    128.     splatPrototypes = terrain.terrainData.splatPrototypes;
    129.    
    130.    
    131.     // check there are 4 textures
    132.     var nTextures : int = splatPrototypes.Length;
    133.    
    134.     if ( nTextures != 4 )
    135.     {
    136.         Debug.LogError( "Error: You must assign 4 textures." );
    137.         return;
    138.     }
    139.    
    140.     // check there are 4 values in the blend points arrays
    141.     var nHeights : int = heightBlendPoints.Length;
    142.    
    143.     if ( nHeights != 4 )
    144.     {
    145.         Debug.LogError( "Error: You must assign 4 values to the Height BlendPoints array." );
    146.         //return;
    147.        
    148.         // example of how arrays should be populated
    149.        
    150.         // heights are normalized values
    151.         heightBlendPoints = new float[4];
    152.         heightBlendPoints[0] = 0.2;
    153.         heightBlendPoints[1] = 0.35;
    154.         heightBlendPoints[2] = 0.5;
    155.         heightBlendPoints[3] = 0.65;
    156.     }
    157.    
    158.     // --
    159.    
    160.    
    161.     var Tw : int = terrainData.heightmapWidth - 1;
    162.     var Th : int = terrainData.heightmapHeight - 1;
    163.    
    164.     var heightMapTexData : float[,] = new float[Tw, Th];
    165.     var slopeMapData : float[,] = new float[Tw, Th];
    166.     var splatMapData : float[,,];
    167.    
    168.     terrainData.alphamapResolution = Tw;
    169.     splatMapData = terrainData.GetAlphamaps(0, 0, Tw, Tw);
    170.    
    171.    
    172.     // Angles to difference...
    173.     var terSize : Vector3 = terrainData.size;
    174.     var slopeBlendMinimum : float = ((terSize.x / Tw) * Mathf.Tan(slopeBlendMinAngle * Mathf.Deg2Rad)) / terSize.y;
    175.     var slopeBlendMaximum : float = ((terSize.x / Tw) * Mathf.Tan(slopeBlendMaxAngle * Mathf.Deg2Rad)) / terSize.y;
    176.    
    177.    
    178.     // ----
    179.    
    180.     var greatestHeight : float = 0.0;
    181.     var xNeighbours : int;
    182.     var yNeighbours : int;
    183.     var xShift : int;
    184.     var yShift : int;
    185.     var xIndex : int;
    186.     var yIndex : int;
    187.     var heightMap : float[,] = terrainData.GetHeights( 0, 0, Tw, Th );
    188.    
    189.     var slopeAngles : float[,] = new float[ Tw, Th ];
    190.    
    191.    
    192.     for (var Ty : int = 0; Ty < Th; Ty++)
    193.     {
    194.         // y...
    195.         if (Ty == 0)
    196.         {
    197.             yNeighbours = 2;
    198.             yShift = 0;
    199.             yIndex = 0;
    200.         }
    201.         else if (Ty == Th - 1)
    202.         {
    203.             yNeighbours = 2;
    204.             yShift = -1;
    205.             yIndex = 1;
    206.         }
    207.         else
    208.         {
    209.             yNeighbours = 3;
    210.             yShift = -1;
    211.             yIndex = 1;
    212.         }
    213.        
    214.         for (var Tx : int = 0; Tx < Tw; Tx++)
    215.         {
    216.             // x...
    217.             if (Tx == 0)
    218.             {
    219.                 xNeighbours = 2;
    220.                 xShift = 0;
    221.                 xIndex = 0;
    222.             }
    223.             else if (Tx == Tw - 1)
    224.             {
    225.                 xNeighbours = 2;
    226.                 xShift = -1;
    227.                 xIndex = 1;
    228.             }
    229.             else
    230.             {
    231.                 xNeighbours = 3;
    232.                 xShift = -1;
    233.                 xIndex = 1;
    234.             }
    235.            
    236.            
    237.             // ----
    238.            
    239.            
    240.             // Get height...
    241.             var h : float = heightMap[ Tx + xIndex + xShift, Ty + yIndex + yShift ];
    242.            
    243.             if (h > greatestHeight)
    244.             {
    245.                 greatestHeight = h;
    246.                 //Debug.Log( h );
    247.             }
    248.            
    249.             // ...and apply to height map...
    250.             heightMapTexData[Tx, Ty] = h;
    251.            
    252.            
    253.             // ----
    254.            
    255.            
    256.             // Calculate slope...
    257.             var tCumulative : float = 0.0f;
    258.             var nNeighbours : float = xNeighbours * yNeighbours - 1;
    259.             var Ny : int;
    260.             var Nx : int;
    261.             var t : float;
    262.            
    263.             for (Ny = 0; Ny < yNeighbours; Ny++)
    264.             {
    265.                 for (Nx = 0; Nx < xNeighbours; Nx++)
    266.                 {
    267.                     // Ignore the index...
    268.                     if (Nx != xIndex || Ny != yIndex)
    269.                     {
    270.                         t = Mathf.Abs( h - heightMap[ Tx + Nx + xShift, Ty + Ny + yShift ] );
    271.                         tCumulative += t;
    272.                     }
    273.                 }
    274.             }
    275.            
    276.             var tAverage : float = tCumulative / nNeighbours;
    277.            
    278.             // ...and apply to the slope map...
    279.             slopeMapData[Tx, Ty] = tAverage;
    280.         }
    281.        
    282.         // Show progress...
    283.         // float completePoints = Ty * Th;
    284.         // float totalPoints = Tw * Th;
    285.         // float percentComplete = (completePoints / totalPoints) * 0.6f;
    286.         // textureProgressDelegate("Procedural Terrain Texture", "Generating height and slope maps. Please wait.", percentComplete);
    287.     }
    288.    
    289.     // Blend slope...
    290.     var sBlended : float;
    291.     var Px : int;
    292.     var Py : int;
    293.    
    294.     for (Py = 0; Py < Th; Py++)
    295.     {
    296.         for (Px = 0; Px < Tw; Px++)
    297.         {
    298.             sBlended = slopeMapData[Px, Py];
    299.            
    300.             if (sBlended < slopeBlendMinimum)
    301.             {
    302.                 sBlended = 0;
    303.             }
    304.             else if (sBlended < slopeBlendMaximum)
    305.             {
    306.                 sBlended = (sBlended - slopeBlendMinimum) / (slopeBlendMaximum - slopeBlendMinimum);
    307.             }
    308.             else if (sBlended > slopeBlendMaximum)
    309.             {
    310.                 sBlended = 1;
    311.             }
    312.            
    313.             slopeMapData[Px, Py] = sBlended;
    314.             splatMapData[Px, Py, 0] = sBlended;
    315.         }
    316.     }
    317.    
    318.     // Blend height maps...
    319.     for (var i : int = 1; i < nTextures; i++)
    320.     {
    321.         for (Py = 0; Py < Th; Py++)
    322.         {
    323.             for (Px = 0; Px < Tw; Px++)
    324.             {
    325.                 var hBlendInMinimum : float = 0;
    326.                 var hBlendInMaximum : float = 0;
    327.                 var hBlendOutMinimum : float = 1;
    328.                 var hBlendOutMaximum : float = 1;
    329.                 var hValue : float;
    330.                 var hBlended : float = 0;
    331.                
    332.                 // --
    333.                
    334.                 // using heights
    335.                
    336.                 if (i > 1)
    337.                 {
    338.                     hBlendInMinimum = parseFloat( heightBlendPoints[i * 2 - 4] );
    339.                     hBlendInMaximum = parseFloat( heightBlendPoints[i * 2 - 3] );
    340.                 }
    341.                
    342.                 if (i < nTextures - 1)
    343.                 {
    344.                     hBlendOutMinimum = parseFloat( heightBlendPoints[i * 2 - 2] );
    345.                     hBlendOutMaximum = parseFloat( heightBlendPoints[i * 2 - 1] );
    346.                 }
    347.                
    348.                 hValue = heightMapTexData[ Px, Py ];
    349.                
    350.                 // --
    351.                
    352.                 if (hValue >= hBlendInMaximum  hValue <= hBlendOutMinimum)
    353.                 {
    354.                     // Full...
    355.                     hBlended = 1;
    356.                 }
    357.                 else if (hValue >= hBlendInMinimum  hValue < hBlendInMaximum)
    358.                 {
    359.                     // Blend in...
    360.                     hBlended = (hValue - hBlendInMinimum) / (hBlendInMaximum - hBlendInMinimum);
    361.                 }
    362.                 else if (hValue > hBlendOutMinimum  hValue <= hBlendOutMaximum)
    363.                 {
    364.                     // Blend out...
    365.                     hBlended = 1 - ((hValue - hBlendOutMinimum) / (hBlendOutMaximum - hBlendOutMinimum));
    366.                 }
    367.                
    368.                 // --
    369.                
    370.                 // Subtract slope...
    371.                 var sValue : float = slopeMapData[ Px, Py ];
    372.                 hBlended -= sValue;
    373.                
    374.                 if (hBlended < 0)
    375.                 {
    376.                     hBlended = 0;
    377.                 }
    378.                
    379.                 splatMapData[ Px, Py, i ] = hBlended;
    380.                
    381.                 // --
    382.             }
    383.         }
    384.     }
    385.    
    386.    
    387.     // Generate splat maps...
    388.     terrainData.SetAlphamaps( 0, 0, splatMapData );
    389.    
    390.    
    391.     // Clean up...
    392.     heightMapTexData = null;
    393.     slopeMapData = null;
    394.     splatMapData = null;
    395.    
    396.     // ----
    397.    
    398.     Debug.Log( "Splatmap Updated using Heights" );
    399. }
    400.  
    401.  
    402. //  ============================================================================
    403.  
    404.  
    405. // -- Modified using Slope Angles --
    406.  
    407.  
    408. public var slopeBlendPoints : float[];
    409.  
    410.  
    411. function TextureTerrainUsingSlopeAngles()
    412. {
    413.     // store a reference to the terrain textures
    414.     splatPrototypes = terrain.terrainData.splatPrototypes;
    415.    
    416.    
    417.     // check there are 4 textures
    418.     var nTextures : int = splatPrototypes.Length;
    419.    
    420.     if ( nTextures != 4 )
    421.     {
    422.         Debug.LogError( "Error: You must assign 4 textures." );
    423.         return;
    424.     }
    425.    
    426.     // check there are 4 values in the blend points arrays
    427.     var nSlopes : int = slopeBlendPoints.Length;
    428.    
    429.     if ( nSlopes != 4 )
    430.     {
    431.         Debug.LogError( "Error: You must assign 4 values to the Slope BlendPoints array." );
    432.         //return;
    433.        
    434.         // example of how arrays should be populated
    435.        
    436.         // slopes are angles in degrees
    437.         slopeBlendPoints = new float[4];
    438.         slopeBlendPoints[0] = 10.0;
    439.         slopeBlendPoints[1] = 15.0;
    440.         slopeBlendPoints[2] = 27.0;
    441.         slopeBlendPoints[3] = 32.0;
    442.     }
    443.    
    444.     // --
    445.    
    446.    
    447.     var Tw : int = terrainData.heightmapWidth - 1;
    448.     var Th : int = terrainData.heightmapHeight - 1;
    449.    
    450.     var heightMapTexData : float[,] = new float[Tw, Th];
    451.     var slopeMapData : float[,] = new float[Tw, Th];
    452.     var splatMapData : float[,,];
    453.    
    454.     terrainData.alphamapResolution = Tw;
    455.     splatMapData = terrainData.GetAlphamaps(0, 0, Tw, Tw);
    456.    
    457.    
    458.     // Angles to difference...
    459.     var terSize : Vector3 = terrainData.size;
    460.     var slopeBlendMinimum : float = ((terSize.x / Tw) * Mathf.Tan(slopeBlendMinAngle * Mathf.Deg2Rad)) / terSize.y;
    461.     var slopeBlendMaximum : float = ((terSize.x / Tw) * Mathf.Tan(slopeBlendMaxAngle * Mathf.Deg2Rad)) / terSize.y;
    462.    
    463.    
    464.     // ----
    465.    
    466.     var greatestHeight : float = 0.0;
    467.     var xNeighbours : int;
    468.     var yNeighbours : int;
    469.     var xShift : int;
    470.     var yShift : int;
    471.     var xIndex : int;
    472.     var yIndex : int;
    473.     var heightMap : float[,] = terrainData.GetHeights( 0, 0, Tw, Th );
    474.    
    475.     var slopeAngles : float[,] = new float[ Tw, Th ];
    476.    
    477.    
    478.     for (var Ty : int = 0; Ty < Th; Ty++)
    479.     {
    480.         // y...
    481.         if (Ty == 0)
    482.         {
    483.             yNeighbours = 2;
    484.             yShift = 0;
    485.             yIndex = 0;
    486.         }
    487.         else if (Ty == Th - 1)
    488.         {
    489.             yNeighbours = 2;
    490.             yShift = -1;
    491.             yIndex = 1;
    492.         }
    493.         else
    494.         {
    495.             yNeighbours = 3;
    496.             yShift = -1;
    497.             yIndex = 1;
    498.         }
    499.        
    500.         for (var Tx : int = 0; Tx < Tw; Tx++)
    501.         {
    502.             // x...
    503.             if (Tx == 0)
    504.             {
    505.                 xNeighbours = 2;
    506.                 xShift = 0;
    507.                 xIndex = 0;
    508.             }
    509.             else if (Tx == Tw - 1)
    510.             {
    511.                 xNeighbours = 2;
    512.                 xShift = -1;
    513.                 xIndex = 1;
    514.             }
    515.             else
    516.             {
    517.                 xNeighbours = 3;
    518.                 xShift = -1;
    519.                 xIndex = 1;
    520.             }
    521.            
    522.            
    523.             // ----
    524.            
    525.            
    526.             // Get height...
    527.             var h : float = heightMap[ Tx + xIndex + xShift, Ty + yIndex + yShift ];
    528.            
    529.             if (h > greatestHeight)
    530.             {
    531.                 greatestHeight = h;
    532.                 //Debug.Log( h );
    533.             }
    534.            
    535.             // ...and apply to height map...
    536.             heightMapTexData[Tx, Ty] = h;
    537.            
    538.            
    539.             // --
    540.            
    541.             // get slope angle instead
    542.            
    543.             var slopeX : float = ( Tx + xIndex + xShift );
    544.             var slopeY : float = ( Ty + yIndex + yShift );
    545.            
    546.             var readPos : Vector2 = new Vector2( slopeX / Tx, slopeY / Ty );
    547.            
    548.             slopeAngles[ Tx, Ty ] = terrainData.GetSteepness( readPos.y, readPos.x ); // y, x : reversed as heightmap is reversed
    549.            
    550.            
    551.             // ----
    552.            
    553.            
    554.             // Calculate slope...
    555.             var tCumulative : float = 0.0f;
    556.             var nNeighbours : float = xNeighbours * yNeighbours - 1;
    557.             var Ny : int;
    558.             var Nx : int;
    559.             var t : float;
    560.            
    561.             for (Ny = 0; Ny < yNeighbours; Ny++)
    562.             {
    563.                 for (Nx = 0; Nx < xNeighbours; Nx++)
    564.                 {
    565.                     // Ignore the index...
    566.                     if (Nx != xIndex || Ny != yIndex)
    567.                     {
    568.                         t = Mathf.Abs( h - heightMap[ Tx + Nx + xShift, Ty + Ny + yShift ] );
    569.                         tCumulative += t;
    570.                     }
    571.                 }
    572.             }
    573.            
    574.             var tAverage : float = tCumulative / nNeighbours;
    575.            
    576.             // ...and apply to the slope map...
    577.             slopeMapData[Tx, Ty] = tAverage;
    578.         }
    579.        
    580.         // Show progress...
    581.         // float completePoints = Ty * Th;
    582.         // float totalPoints = Tw * Th;
    583.         // float percentComplete = (completePoints / totalPoints) * 0.6f;
    584.         // textureProgressDelegate("Procedural Terrain Texture", "Generating height and slope maps. Please wait.", percentComplete);
    585.     }
    586.    
    587.     // Blend slope...
    588.     var sBlended : float;
    589.     var Px : int;
    590.     var Py : int;
    591.    
    592.     for (Py = 0; Py < Th; Py++)
    593.     {
    594.         for (Px = 0; Px < Tw; Px++)
    595.         {
    596.             sBlended = slopeMapData[Px, Py];
    597.            
    598.             if (sBlended < slopeBlendMinimum)
    599.             {
    600.                 sBlended = 0;
    601.             }
    602.             else if (sBlended < slopeBlendMaximum)
    603.             {
    604.                 sBlended = (sBlended - slopeBlendMinimum) / (slopeBlendMaximum - slopeBlendMinimum);
    605.             }
    606.             else if (sBlended > slopeBlendMaximum)
    607.             {
    608.                 sBlended = 1;
    609.             }
    610.            
    611.             slopeMapData[Px, Py] = sBlended;
    612.             splatMapData[Px, Py, 0] = sBlended;
    613.         }
    614.     }
    615.    
    616.     // Blend height maps...
    617.     for (var i : int = 1; i < nTextures; i++)
    618.     {
    619.         for (Py = 0; Py < Th; Py++)
    620.         {
    621.             for (Px = 0; Px < Tw; Px++)
    622.             {
    623.                 var hBlendInMinimum : float = 0;
    624.                 var hBlendInMaximum : float = 0;
    625.                 var hBlendOutMinimum : float = 1;
    626.                 var hBlendOutMaximum : float = 1;
    627.                 var hValue : float;
    628.                 var hBlended : float = 0;
    629.                
    630.                 // --
    631.                
    632.                 /*
    633.                
    634.                 // using heights
    635.                
    636.                 if (i > 1)
    637.                 {
    638.                     hBlendInMinimum = parseFloat( heightBlendPoints[i * 2 - 4] );
    639.                     hBlendInMaximum = parseFloat( heightBlendPoints[i * 2 - 3] );
    640.                 }
    641.                
    642.                 if (i < nTextures - 1)
    643.                 {
    644.                     hBlendOutMinimum = parseFloat( heightBlendPoints[i * 2 - 2] );
    645.                     hBlendOutMaximum = parseFloat( heightBlendPoints[i * 2 - 1] );
    646.                 }
    647.                
    648.                 */
    649.                
    650.                 // --
    651.                
    652.                 // using slope angles
    653.                
    654.                 if (i > 1)
    655.                 {
    656.                     hBlendInMinimum = parseFloat( slopeBlendPoints[i * 2 - 4] );
    657.                     hBlendInMaximum = parseFloat( slopeBlendPoints[i * 2 - 3] );
    658.                 }
    659.                
    660.                 if (i < nTextures - 1)
    661.                 {
    662.                     hBlendOutMinimum = parseFloat( slopeBlendPoints[i * 2 - 2] );
    663.                     hBlendOutMaximum = parseFloat( slopeBlendPoints[i * 2 - 1] );
    664.                 }
    665.                
    666.                
    667.                 // --
    668.                
    669.                 //using heights
    670.                 //hValue = heightMapTexData[ Px, Py ];
    671.                
    672.                 // now using slope angles
    673.                 hValue = slopeAngles[ Px, Py ];
    674.                
    675.                 // normalize all angle values to 90 degrees
    676.                 var maxAngle : float = 90.0;
    677.                
    678.                 hBlendInMinimum /= maxAngle;
    679.                 hBlendInMaximum /= maxAngle;
    680.                 hBlendOutMinimum /= maxAngle;
    681.                 hBlendOutMaximum /= maxAngle;
    682.                
    683.                 hValue /= maxAngle;
    684.                
    685.                
    686.                 // --
    687.                
    688.                
    689.                 if (hValue >= hBlendInMaximum  hValue <= hBlendOutMinimum)
    690.                 {
    691.                     // Full...
    692.                     hBlended = 1;
    693.                 }
    694.                 else if (hValue >= hBlendInMinimum  hValue < hBlendInMaximum)
    695.                 {
    696.                     // Blend in...
    697.                     hBlended = (hValue - hBlendInMinimum) / (hBlendInMaximum - hBlendInMinimum);
    698.                 }
    699.                 else if (hValue > hBlendOutMinimum  hValue <= hBlendOutMaximum)
    700.                 {
    701.                     // Blend out...
    702.                     hBlended = 1 - ((hValue - hBlendOutMinimum) / (hBlendOutMaximum - hBlendOutMinimum));
    703.                 }
    704.                
    705.                 // --
    706.                
    707.                 // Subtract slope...
    708.                 var sValue : float = slopeMapData[ Px, Py ];
    709.                 hBlended -= sValue;
    710.                
    711.                 if (hBlended < 0)
    712.                 {
    713.                     hBlended = 0;
    714.                 }
    715.                
    716.                 splatMapData[ Px, Py, i ] = hBlended;
    717.                
    718.                 // --
    719.             }
    720.         }
    721.     }
    722.    
    723.    
    724.     // Generate splat maps...
    725.     terrainData.SetAlphamaps( 0, 0, splatMapData );
    726.    
    727.    
    728.     // Clean up...
    729.     slopeMapData = null;
    730.     splatMapData = null;
    731.     slopeAngles = null;
    732.    
    733.     // ----
    734.    
    735.     Debug.Log( "Splatmap Updated using Slope Angles" );
    736. }
    737.  
    738.  
    739. // =================================================================================
    740.  
     
    Last edited: Nov 11, 2013
  2. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    I posted this question as I have spent weeks trying to write my own method of blending textures between heights.

    I was only setting absolute texture values based on simple conditionals :

    Code (csharp):
    1.  
    2.             // --
    3.            
    4.             var terrTex : int = 0;
    5.            
    6.             if ( steepness < slope1 )
    7.             {
    8.                 terrTex = 1;
    9.             }
    10.             else if ( steepness < slope2 )
    11.             {
    12.                 terrTex = 2;
    13.             }
    14.             else if ( steepness < slope3 )
    15.             {
    16.                 terrTex = 3;
    17.             }
    18.            
    19.             // --
    20.            
    21.             switch( terrTex )
    22.             {
    23.                 case 1 :
    24.                     alphas[ w, h, 0 ] = 0;
    25.                     alphas[ w, h, 1 ] = 1;
    26.                     alphas[ w, h, 2 ] = 0;
    27.                     alphas[ w, h, 3 ] = 0;
    28.                 break;
    29.                
    30.                 case 2 :
    31.                     alphas[ w, h, 0 ] = 0;
    32.                     alphas[ w, h, 1 ] = 0;
    33.                     alphas[ w, h, 2 ] = 1;
    34.                     alphas[ w, h, 3 ] = 0;
    35.                 break;
    36.                
    37.                 case 3 :
    38.                     alphas[ w, h, 0 ] = 0;
    39.                     alphas[ w, h, 1 ] = 0;
    40.                     alphas[ w, h, 2 ] = 0;
    41.                     alphas[ w, h, 3 ] = 1;
    42.                 break;
    43.                
    44.                 default :
    45.                     alphas[ w, h, 0 ] = 1;
    46.                     alphas[ w, h, 1 ] = 0;
    47.                     alphas[ w, h, 2 ] = 0;
    48.                     alphas[ w, h, 3 ] = 0;
    49.                 break;
    50.             }
    51.            
    52.             // --
    53.  
    After struggling with how to blend inbetween these absolute values, I looked at the TerrainToolkit and thought there may be a way to adapt their script (as illustrated in my questions' code).

    However I just went back to my original script, and the solution was so simple. I just had to add conditions for when the slope angle was between textures, and calculate alphas based on those differences.

    Code (csharp):
    1.  
    2.             // --
    3.            
    4.            
    5.             var cond : int = 0;
    6.            
    7.             if ( steepness <= slopeAngles[ 1 ] )
    8.             {
    9.                 cond = 1;
    10.             }
    11.             else if ( steepness > slopeAngles[ 1 ]  steepness <= slopeAngles[ 2 ] )
    12.             {
    13.                 cond = 2;
    14.             }
    15.             else if ( steepness > slopeAngles[ 2 ]  steepness <= slopeAngles[ 3 ] )
    16.             {
    17.                 cond = 3;
    18.             }
    19.             else if ( steepness > slopeAngles[ 3 ]  steepness <= slopeAngles[ 4 ] )
    20.             {
    21.                 cond = 4;
    22.             }
    23.             else if ( steepness > slopeAngles[ 4 ]  steepness <= slopeAngles[ 5 ] )
    24.             {
    25.                 cond = 5;
    26.             }
    27.             else if ( steepness > slopeAngles[ 5 ]  steepness <= slopeAngles[ 6 ] )
    28.             {
    29.                 cond = 6;
    30.             }
    31.            
    32.            
    33.             // --
    34.            
    35.            
    36.             var curr : float;
    37.             var max : float;
    38.            
    39.             var alpha1 : float;
    40.             var alpha2 : float;
    41.            
    42.            
    43.             switch( cond )
    44.             {
    45.                 case 1 :
    46.                     alphas[ w, h, 0 ] = 0;
    47.                     alphas[ w, h, 1 ] = 1;
    48.                     alphas[ w, h, 2 ] = 0;
    49.                     alphas[ w, h, 3 ] = 0;
    50.                 break;
    51.                
    52.                 case 2 :
    53.                     curr = steepness - slopeAngles[ 1 ];
    54.                     max = slopeAngles[ 2 ] - slopeAngles[ 1 ];
    55.                    
    56.                     alpha1 = curr / max;
    57.                     alpha2 = 1.0 - alpha1;
    58.                    
    59.                     alphas[ w, h, 0 ] = 0;
    60.                     alphas[ w, h, 1 ] = alpha2;
    61.                     alphas[ w, h, 2 ] = alpha1;
    62.                     alphas[ w, h, 3 ] = 0;
    63.                 break;
    64.                
    65.                 case 3 :
    66.                     alphas[ w, h, 0 ] = 0;
    67.                     alphas[ w, h, 1 ] = 0;
    68.                     alphas[ w, h, 2 ] = 1;
    69.                     alphas[ w, h, 3 ] = 0;
    70.                 break;
    71.                
    72.                 case 4 :
    73.                     curr = steepness - slopeAngles[ 3 ];
    74.                     max = slopeAngles[ 4 ] - slopeAngles[ 3 ];
    75.                    
    76.                     alpha1 = curr / max;
    77.                     alpha2 = 1.0 - alpha1;
    78.                    
    79.                     alphas[ w, h, 0 ] = 0;
    80.                     alphas[ w, h, 1 ] = 0;
    81.                     alphas[ w, h, 2 ] = alpha2;
    82.                     alphas[ w, h, 3 ] = alpha1;
    83.                 break;
    84.                
    85.                 case 5 :
    86.                     alphas[ w, h, 0 ] = 0;
    87.                     alphas[ w, h, 1 ] = 0;
    88.                     alphas[ w, h, 2 ] = 0;
    89.                     alphas[ w, h, 3 ] = 1;
    90.                 break;
    91.                
    92.                 case 6 :
    93.                     curr = steepness - slopeAngles[ 5 ];
    94.                     max = slopeAngles[ 6 ] - slopeAngles[ 5 ];
    95.                    
    96.                     alpha1 = curr / max;
    97.                     alpha2 = 1.0 - alpha1;
    98.                    
    99.                     alphas[ w, h, 0 ] = alpha1;
    100.                     alphas[ w, h, 1 ] = 0;
    101.                     alphas[ w, h, 2 ] = 0;
    102.                     alphas[ w, h, 3 ] = alpha2;
    103.                 break;
    104.                
    105.                 default :
    106.                     alphas[ w, h, 0 ] = 1;
    107.                     alphas[ w, h, 1 ] = 0;
    108.                     alphas[ w, h, 2 ] = 0;
    109.                     alphas[ w, h, 3 ] = 0;
    110.                 break;
    111.             }
    112.            
    113.             // --
    114.  
    Problem solved, terrain is now painted and blending based on slope angles !

    =]