[小明學Shader]15.基於Grid的地形混合shader


1.寫在前面

  好久沒有寫博客了,最近面試不太順利,認識到應該把學習心得或者說是結果都落實到博客上來,一來加深印象,二來有利於自我展示.

  本片博客的內容是講地形紋理混合,是關於手游sgl大地圖的shader實現.

  slg大地圖,如cok,是很大的.在渲染時,只渲染屏幕周圍的一部分.

  在渲染屏幕地形時,會提供一組地形數據,shader會根據地形數據對地形進行混合.

2.混合方法

  混合使用的方法是非常常見的紋理混合.

  基本原理是為shader提供多張可以選用的地形貼圖.然后根據一張alpha貼圖或者其它方式來決定紋理的如何混合.即選用哪個層級的地形紋理進行渲染.

3.紋理選擇

  前文有提到,本shader是在slg游戲中做地形混合的.

  在手游slg中,如cok,地形只是渲染在一個平面上的.

  如下圖所示,其中每一個小的方格可以代表一個地形單位.

  

  而每一個小的地形單位,可以用一個標記位來表示地形所使用的紋理的種類.

5.選擇紋理混合信息標識

  那么要怎么告訴shader在渲染時要使用哪個紋理呢,

  本文所使用的方法是通過頂點色.

  在Unity當中,為每一個Mesh默認提供了一個頂點數組,一個三角形數組和一個頂點顏色數組,值得一提的是每一個Mesh還都擁有四個UV數組.

  頂點色有rgba四個通道,再加上1-(rgba的和)剛好可以用來表示五層紋理的混合參數.其中1-(rgba和)用來表示默認層紋理的混合參數.

6.設置頂點顏色 

  決定了采用頂點色來表示混合參數之后,我們還要決定把哪些頂點設置顏色.

  以本文所用的square地形為例,每一個小的地形Cell都有兩個三角形,四個頂點組成,那么既然如此,我們只需要把這四個頂點的頂點色中,代表該地塊紋理的通道值+1即可.

  在遍歷完所有地塊,設置完定點后,需要對定點顏色執行約束操作,按比例縮放,保證和值不超過1.

  將得到的頂點色賦值給mesh即可.

 

7.效果示意:

8.參考

  https://zhuanlan.zhihu.com/p/26383778

  https://www.cnblogs.com/luxishi/p/6670487.html

9.源碼:

  shader:

  

 1 Shader "SlpatMap/TerrainLab"
 2 {
 3     Properties
 4     {
 5         _Splat0 ("_SlpatTex0", 2D) = "white" {}
 6         _Splat1 ("_SlpatTex1", 2D) = "white" {}
 7         _Splat2 ("_SlpatTex2", 2D) = "white" {}
 8         _Splat3 ("_SlpatTex3", 2D) = "white" {}
 9         _Splat4 ("_SlpatTex4", 2D) = "white" {}
10     }
11     SubShader
12     {
13         Tags { "RenderType"="Opaque" }
14         LOD 100
15 
16         Pass
17         {
18             CGPROGRAM
19             #pragma vertex vert
20             #pragma fragment frag
21 
22             #include "UnityCG.cginc"
23 
24             struct appdata
25             {
26                 float4 vertex : POSITION;
27                 float2 texcoord : TEXCOORD0;
28                 fixed4 color : COLOR;
29             };
30 
31             struct v2f
32             {
33                 float4 vertex : SV_POSITION;
34                 float2  uv[5] : TEXCOORD0;
35                 fixed4 color : COLOR0;
36                 fixed color2 : COLOR1;
37             };
38 
39         
40             sampler2D _Splat0;
41             sampler2D _Splat1;
42             sampler2D _Splat2;
43             sampler2D _Splat3;
44             sampler2D _Splat4;
45 
46             float4 _Splat0_ST;
47             float4 _Splat1_ST;
48             float4 _Splat2_ST;
49             float4 _Splat3_ST;
50             float4 _Splat4_ST;
51             
52             v2f vert (appdata v)
53             {
54                 v2f o;
55                 o.vertex = UnityObjectToClipPos(v.vertex);
56                 o.uv[0] = TRANSFORM_TEX(v.texcoord, _Splat0);
57                 o.uv[1] = TRANSFORM_TEX(v.texcoord, _Splat1);
58                 o.uv[2] = TRANSFORM_TEX(v.texcoord, _Splat2);
59                 o.uv[3] = TRANSFORM_TEX(v.texcoord, _Splat3);
60                 o.uv[4] = TRANSFORM_TEX(v.texcoord, _Splat4);
61                 o.color = v.color;
62                 o.color2 = (1 - (v.color.r + v.color.g + v.color.b + v.color.a));
63                 return o;
64             }
65             
66             fixed4 frag (v2f i) : SV_Target
67             {
68                 fixed3 zero = fixed3(0, 0, 0);
69                 fixed3 splat1Col = i.color.r <= 0.001 ? zero : tex2D(_Splat0, i.uv[0]).xyz * i.color.r;
70                 fixed3 splat2Col = i.color.g <= 0.001 ? zero : tex2D(_Splat1, i.uv[1]).xyz * i.color.g;
71                 fixed3 splat3Col = i.color.b <= 0.001 ? zero : tex2D(_Splat2, i.uv[2]).xyz * i.color.b;
72                 fixed3 splat4Col = i.color.a <= 0.001 ? zero : tex2D(_Splat3, i.uv[3]).xyz * i.color.a;
73                 fixed3 splat5Col = i.color2 <= 0.001 ? zero : tex2D(_Splat4, i.uv[4]).xyz * i.color2;
74                 fixed4 col;
75                 col.xyz = splat1Col + splat2Col + splat3Col + splat4Col + splat5Col;
76                 col.w = 1;
77                 return col;
78             }
79             ENDCG
80         }
81     }
82 }
View Code

  c#代碼:

 1 using System.Collections.Generic;
 2 using UnityEngine;
 3 
 4 public class SquarePlaneComponent : MonoBehaviour
 5 {
 6 
 7     static int[,] terrainType = new int[,]{
 8         {0,0,0,1,1,1,1,1,1,1},
 9         {1,1,1,1,1,1,1,1,1,1},
10         {1,1,1,1,1,1,1,1,1,1},
11         {1,1,2,2,1,1,1,1,1,1},
12         {1,1,2,2,3,3,3,3,3,1},
13         {1,1,1,2,1,1,1,1,1,1},
14         {1,1,1,1,1,1,1,1,1,0},
15         {1,1,1,1,1,1,1,1,1,0},
16         {1,1,1,1,1,1,1,1,1,0},
17         {1,1,1,1,1,1,1,1,1,1},
18 
19     };
20     public int rows = 10;
21 
22     public int cols = 10;
23 
24     public MeshRenderer meshRenderer;
25 
26     public MeshFilter meshFilter;
27 
28 
29     public int[] vertGridMappingArr;
30 
31     [ContextMenu("UpdateColorInfo")]
32     public void UpdateUVInfo()
33     {
34         var vertices = meshFilter.sharedMesh.vertices;
35         var colors = new Color[vertices.Length];
36         var uv = meshFilter.sharedMesh.uv;
37         var colorsV = new Vector4[vertices.Length];
38         var VRowLength = rows + 1;
39 
40         var col = terrainType.GetLength(0);
41         var row = terrainType.GetLength(1);
42 
43         for (int i = 0; i < col; i++)
44         {
45             for (int j = 0; j < row; j++)
46             {
47                 var index = (i + 1) * VRowLength - j - 1;
48                 var leftTop = index;
49                 var rightTop = index - 1;
50                 var leftBottom = index + VRowLength;
51                 var rightBottom = index + VRowLength - 1;
52 
53                 var indexList = new List<int>() { leftTop, rightTop, leftBottom, rightBottom };
54                 foreach (var t in indexList)
55                 {
56                     colorsV[t] = Set(colorsV[t], terrainType[i, j]);
57                 }
58             }
59         }
60 
61         for (int i = 0; i < vertices.Length && i < colors.Length; i++)
62         {
63             var cv = colorsV[i] / colorsV[i].magnitude;
64             colors[i] = new Color(cv.x, cv.y, cv.z, cv.w);
65         }
66         meshFilter.sharedMesh.colors = colors;
67     }
68 
69     public Vector4 Set(Vector4 v, int type)
70     {
71         switch (type)
72         {
73             case 0:
74                 v.x += 1;
75                 break;
76             case 1:
77                 v.y += 1;
78                 break;
79             case 2:
80                 v.z += 1;
81                 break;
82             case 3:
83                 v.w += 1;
84                 break;
85         }
86         return v;
87     }
88 }
View Code

 

  

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM