Unity Shader實現(xiàn)翻書效果
今天實現(xiàn)一個簡單的翻書的效果,話不多說,先上一張效果圖:
這里就隨便用的一張紋理了,我們還是稱為“翻木板”吧,哈哈。

實現(xiàn)過程:
其實這個效果實現(xiàn)起來還是挺簡單的,大概思路其實就是 讓所有頂點都繞Z軸旋轉(zhuǎn),并且通過正余弦使之帶有一點弧度。
下面開始讓我們一步一步的實現(xiàn)該效果。
首先打開Unity新建一個工程,場景,并且創(chuàng)建一個名為openBookEffect的Shader文件,刪掉原本多余的代碼。
第一步,我們先讓它繞z軸旋轉(zhuǎn)起來
這里就要用到一個旋轉(zhuǎn)矩陣了,讓頂點左乘該矩陣,就能得到旋轉(zhuǎn)之后的位置了。(ps:這里就不詳細的解釋旋轉(zhuǎn)矩陣怎么推導(dǎo)來的了,有興趣的可以去百度了解一下。)
旋轉(zhuǎn)矩陣有3種:
1.繞x軸旋轉(zhuǎn):

2.繞y軸旋轉(zhuǎn)

3.繞z軸旋轉(zhuǎn)

很明顯,我們這里需要用到的是第三個 繞z軸旋轉(zhuǎn)的矩陣。下面我們通過代碼來構(gòu)建一個旋轉(zhuǎn)矩陣并使之旋轉(zhuǎn)一定的角度:
Properties
{
_MainTex ("Texture", 2D) = "white" {}
//旋轉(zhuǎn)角度
_Angle("Angle",Range(0,180))=0
}
....
sampler2D _MainTex;
//角度
float _Angle;
//頂點著色器
v2f vert (appdata v)
{
v2f o;
float s;
float c;
//通過該方法可以計算出該角度的正余弦值
sincos(radians(_Angle),s,c);
//旋轉(zhuǎn)矩陣
float4x4 rotateMatrix={
c ,s,0,0,
-s,c,0,0,
0 ,0,1,0,
0 ,0,0,1
};
//頂點左乘以旋轉(zhuǎn)矩陣
v.vertex = mul(rotateMatrix,v.vertex);
//模型空間轉(zhuǎn)換到裁剪空間
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
....
修改 _Angle 大小,來旋轉(zhuǎn)平面,如圖:

通過測試發(fā)現(xiàn),這樣的旋轉(zhuǎn)并不是我們想要的效果,此時旋轉(zhuǎn)的軸在中心,我們想讓它的旋轉(zhuǎn)軸在最左邊,此時就需要把所有頂點在旋轉(zhuǎn)之前都往左偏移5個單位,旋轉(zhuǎn)完成之后再向右偏移5個單位就可以達到我們想要的效果了,代碼如下:
v2f vert (appdata v)
{
v2f o;
//旋轉(zhuǎn)之前向左偏移5個單位
v.vertex -= float4(5,0,0,0);
float s;
float c;
//通過該方法可以計算出該角度的正余弦值
sincos(radians(_Angle),s,c);
//旋轉(zhuǎn)矩陣
float4x4 rotateMatrix={
c ,s,0,0,
-s,c,0,0,
0 ,0,1,0,
0 ,0,0,1
};
//頂點左乘以旋轉(zhuǎn)矩陣
v.vertex = mul(rotateMatrix,v.vertex);
//旋轉(zhuǎn)之后偏移回來
v.vertex += float4(5,0,0,0);
//模型空間轉(zhuǎn)換到裁剪空間
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}

現(xiàn)在有一點翻書的樣子了,但是現(xiàn)在的翻書效果太生硬了,為了接近真實的翻書效果,我們就需要通過正余弦函數(shù)修改頂點的y坐標,來達到一個弧度的效果。
v2f vert (appdata v)
{
v2f o;
//旋轉(zhuǎn)之前向右偏移5個單位
v.vertex -= float4(5,0,0,0);
float s;
float c;
//通過該方法可以計算出該角度的正余弦值
sincos(radians(_Angle),s,c);
//旋轉(zhuǎn)矩陣
float4x4 rotateMatrix={
c ,s,0,0,
-s,c,0,0,
0 ,0,1,0,
0 ,0,0,1
};
//根據(jù)x坐標,通過正弦函數(shù)計算出 y坐標的正弦值, _WaveLength 控制波長, 振幅就跟隨角度正弦值動態(tài)變化
v.vertex.y = sin(v.vertex.x*_WaveLength) * s ;
//頂點左乘以旋轉(zhuǎn)矩陣
v.vertex = mul(rotateMatrix,v.vertex);
//旋轉(zhuǎn)之后偏移回來
v.vertex += float4(5,0,0,0);
//模型空間轉(zhuǎn)換到裁剪空間
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
效果如下:


現(xiàn)在看著效果是不是闊以了。感覺效果還挺不錯的,但是還沒完,我們仔細觀察會發(fā)現(xiàn)“翻書”的過程,背面有點不真實,不應(yīng)該是該紋理的反面,而是另一張新的紋理,此時我們該怎么辦呢?
其實很簡單,只需要把正面和反面分開渲染就可以了,一個Pass渲染正面,一個Pass渲染背面。
首先我們需要通過 Cull 指令剔除不需要渲染的那一面。
完整代碼如下:
Shader "Learn Unity Shader/openBook"
{
Properties
{
//正面紋理
_MainTex ("Texture", 2D) = "white" {}
//背面紋理
_SecTex("SecTex",2D)="White"{}
//旋轉(zhuǎn)角度
_Angle("Angle",Range(0,180))=0
//波長
_WaveLength("WaveLength",Range(-1,1))=0
}
SubShader
{
Pass
{
//剔除背面
Cull Back
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
//角度
float _Angle;
//波長
float _WaveLength;
v2f vert (appdata v)
{
v2f o;
//旋轉(zhuǎn)之前向右偏移5個單位
v.vertex -= float4(5,0,0,0);
float s;
float c;
//通過該方法可以計算出該角度的正余弦值
sincos(radians(_Angle),s,c);
//旋轉(zhuǎn)矩陣
float4x4 rotateMatrix={
c ,s,0,0,
-s,c,0,0,
0 ,0,1,0,
0 ,0,0,1
};
//根據(jù)x坐標,通過正弦函數(shù)計算出 y坐標的正弦值, _WaveLength 控制波長, 振幅就跟隨角度正弦值動態(tài)變化
v.vertex.y = sin(v.vertex.x*_WaveLength) * s ;
//頂點左乘以旋轉(zhuǎn)矩陣
v.vertex = mul(rotateMatrix,v.vertex);
//旋轉(zhuǎn)之后偏移回來
v.vertex += float4(5,0,0,0);
//模型空間轉(zhuǎn)換到裁剪空間
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
Pass
{
//剔除正面
Cull Front
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
//角度
float _Angle;
//波長
float _WaveLength;
sampler2D _SecTex;
float4 _SecTex_ST;
v2f vert (appdata v)
{
v2f o;
//旋轉(zhuǎn)之前向右偏移5個單位
v.vertex -= float4(5,0,0,0);
float s;
float c;
//通過該方法可以計算出該角度的正余弦值
sincos(radians(_Angle),s,c);
//旋轉(zhuǎn)矩陣
float4x4 rotateMatrix={
c ,s,0,0,
-s,c,0,0,
0 ,0,1,0,
0 ,0,0,1
};
//根據(jù)x坐標,通過正弦函數(shù)計算出 y坐標的正弦值, _WaveLength 控制波長, 振幅就跟隨角度正弦值動態(tài)變化
v.vertex.y = sin(v.vertex.x*_WaveLength) * s ;
//頂點左乘以旋轉(zhuǎn)矩陣
v.vertex = mul(rotateMatrix,v.vertex);
//旋轉(zhuǎn)之后偏移回來
v.vertex += float4(5,0,0,0);
//模型空間轉(zhuǎn)換到裁剪空間
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_SecTex, i.uv);
return col;
}
ENDCG
}
}
}
最終效果:

參數(shù)參考:

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
原生實現(xiàn)C#與Lua相互調(diào)用方法(Unity3D可用)
Lua是一種很好的擴展性語言,Lua解釋器被設(shè)計成一個很容易嵌入到宿主程序的庫,下面這篇文章主要給大家介紹了關(guān)于原生實現(xiàn)C#與Lua相互調(diào)用方法,Unity3D可用的相關(guān)資料,需要的朋友可以參考下2022-04-04
C#使用NAudio實現(xiàn)監(jiān)聽系統(tǒng)聲音
這篇文章主要為大家詳細介紹了C#如何使用NAudio實現(xiàn)監(jiān)聽系統(tǒng)聲音并屏蔽麥克風(fēng)其他聲音,文中的示例代碼講解詳細,有需要的小伙伴可以參考下2024-02-02
解析數(shù)字簽名的substring結(jié)構(gòu)(獲取數(shù)字簽名時間)
解析數(shù)字簽名的substring結(jié)構(gòu),大家參考使用吧2013-12-12

