大場景,遠處景物的閃現會很讓遊玩的玩家出戲。
地鐵跑酷和動森用了不同的方式來抵消這種問題。
之前的內容
UnityShader 基礎(21)-空間漸變-距離剔除透明
介紹了如何利用空間位置“o.WordPos” 進行顏色著色。
這壹節在頂點片段中 修改 "o.vertex”模型坐標數據就可以改變模型形狀。
之前的地鐵跑酷遊戲
整個場景其實是壹條直線,道路的左右彎道,上下坡道,是用Shader彎曲模型頂點做到的。
首先創建兩個控制屬性
_SwerveX("左右彎道", Range(-0.01,0.01)) = 0.0 _SwerveY("上坡下破", Range(-0.01,0.01)) = 0.0
在頂點片段中加入以下修改頂點程序,總***分3步
第壹步,首先把模型空間頂點,轉為世界空間頂點
//獲取模型的空間坐標 float3 WordPos = mul(unity_ObjectToWorld, v.vertex); //----左右坐標作為彎道 ---- //依據Z坐標求平方獲取彎曲曲線,越遠離世界坐標原點,彎曲效果越明顯。 //最後乘以左右彎道彎曲方向,和彎曲強度 WordPos.x +=pow(WordPos.z, 2)*_SwerveX; //方法與上面相同,改變Y軸,獲得上下坡效果 WordPos.y += pow(WordPos.z, 2)*_SwerveY;
第二步,在模型空間下,依據空間坐標修改頂點
//修正模型位置,WordPos 不包含物體自身的空間位移 WordPos -= mul(unity_ObjectToWorld, float4(0, 0, 0, 1));
第三步把修改結果轉回模型空間,修改原始模型數據。
//修改世界頂點轉回物體自身頂點。 v.vertex = mul(unity_WorldToObject, WordPos);
使用效果:
動態效果:
Shader代碼
Shader "CRLuo/CRLuo_Teaching38_Vertex_PathBend_Base" { Properties { _MainTex ("顏色紋理", 2D) = "white" {} _SwerveX("左右彎曲程度", Range(-0.003,0.003)) = 0.0 _SwerveY("上下彎曲程度", Range(-0.003,0.003)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; //獲取模型第壹套UV float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; UNITY_FOG_COORDS(4) }; //顏色紋理 sampler2D _MainTex; float _SwerveX; float _SwerveY; v2f vert (appdata v) { v2f o; o.uv = v.uv; //獲取模型的空間坐標 float3 WordPos = mul(unity_ObjectToWorld, v.vertex); //左右左右坐標作為彎道 //依據Z坐標求平方獲取彎曲曲線,越遠離世界坐標原點,彎曲效果越明顯。 //最後乘以左右彎道彎曲方向,和彎曲強度 WordPos.x +=pow(WordPos.z, 2)*_SwerveX; //方法與上面相同,改變Y軸,獲得上下坡效果 WordPos.y += pow(WordPos.z, 2)*_SwerveY; //修正模型位置,WordPos 不包含物體自身的空間位移 WordPos -= mul(unity_ObjectToWorld, float4(0, 0, 0, 1)); //修改世界頂點轉回物體自身頂點。 v.vertex = mul(unity_WorldToObject, WordPos); //轉換為裁切空間 o.vertex = UnityObjectToClipPos(v.vertex); UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { //獲取顏色貼圖 fixed4 col = tex2D(_MainTex, i.uv); // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } } }
動物森友會使用的類似球形的地圖,來抵消模型的突然出現。
可以使用X和Z軸坐標來影響模型點Y的位置。
核心代碼就是
把
WordPos.x +=pow(WordPos.z, 2)*_SwerveX; WordPos.y += pow(WordPos.z, 2)*_SwerveY;
替換為
//Y軸扭 = 曲依據XZ坐標變化 WordPos.y -= pow(WordPos.x, 2)*_BendY; WordPos.y -= pow(WordPos.z, 2)*_BendY;
使用效果:
動態效果
Shader代碼
Shader "CRLuo/CRLuo_Teaching39_Vertex_WorldBend_Base" { Properties { [NoScaleOffset] _MainTex ("顏色紋理", 2D) = "white" {} _BendY("彎曲程度", Range(0,0.01)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; //獲取模型第壹套UV float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; //定義頂點世界變量 float4 WordData : TEXCOORD1; float4 vertex : SV_POSITION; UNITY_FOG_COORDS(4) }; //顏色紋理 sampler2D _MainTex; float _BendY; v2f vert (appdata v) { v2f o; o.uv = v.uv; float3 WordPos = mul(unity_ObjectToWorld, v.vertex); //獲取Y軸坐標 o.WordData.x = WordPos.y; //Y軸扭 = 曲依據XZ坐標變化 WordPos.y -= pow(WordPos.x, 2)*_BendY; WordPos.y -= pow(WordPos.z, 2)*_BendY; //獲取位移位置 WordPos -= mul(unity_ObjectToWorld, float4(0, 0, 0, 1)); //修改世界頂點轉回物體自身頂點。 v.vertex = mul(unity_WorldToObject, WordPos); //轉換為裁切空間 o.vertex = UnityObjectToClipPos(v.vertex); UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { //獲取顏色貼圖 fixed4 col = tex2D(_MainTex, i.uv); // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } } }
後記:
這裏使用了最簡單粗暴的平方曲線來模擬圓弧,
後面會討論更多的曲線公式與算法。