zoukankan      html  css  js  c++  java
  • [小明学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

      

     

  • 相关阅读:
    关于观察者模式和发布/订阅模式
    git:error: Your local changes to the following files would be overwritten by merge:
    node中几个路径的梳理
    centOS 开启服务器后无法访问(大坑啊)
    文件上传简记
    自建nodejs服务器(一:有个服务器)
    nodejs上使用sql
    express笔记
    windows下node配置npm全局路径(踩坑)
    DropMaster
  • 原文地址:https://www.cnblogs.com/WongSiuming/p/11018866.html
Copyright © 2011-2022 走看看