UnityShader使用Plane实现翻书效果
lijiao 人气:0之前在网上看到一个Shadr可以实现旋转效果,就拿来实现一个翻书效果。解决办法是用不同模型的显示与隐藏,像序列帧一样,为了实现效果感觉实现起来很繁琐且占用资源,后期优化可考虑用对象池解决。今天就试着用vertex shader来实现一下,互相交流学习,大神勿喷。
实现简单的翻书效果大概需要三步:
1.Plane的扭曲
2.Plane的旋转
3.正反面的采样
Plane的扭曲:
翻书的效果大概是,中间向外突出,X轴方向的正方向会向后偏移。
X轴负方向边沿是保持不动的,且扭曲程度跟随旋转角度增加又减小,90度为最大值。
Plane的旋转:
根据Plane的顶点X的范围(-5,5)
Plane的贴图采样:
用了两个Pass通道来实现,一个是后面剔除,一个是前面剔除。分别对两个图片采样。
下面是Shader
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Personal/PageTurning" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex("MainTex",2D)="White"{} _SecTex("SecTex",2D)="White"{} _Angle("Angle",Range(0,180))=0 _Warp("Warp",Range(0,10))=0 _WarpPos("WarpPos",Range(0,1))=0 _Downward("Downward",Range(0,1))=0 } SubShader { pass { Cull Back CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; }; fixed4 _Color; float _Angle; float _Warp; float _Downward; float _WarpPos; sampler2D _MainTex; float4 _MainTex_ST; v2f vert(appdata_base v) { v2f o; v.vertex += float4(5,0,0,0); float s; float c; sincos(radians(-_Angle),s,c); float4x4 rotate={ c,s,0,0, -s,c,0,0, 0,0,1,0, 0,0,0,1}; float rangeF=saturate(1 - abs(90-_Angle)/90); v.vertex.y += -_Warp*sin(v.vertex.x*0.4-_WarpPos* v.vertex.x)*rangeF; v.vertex.x -= rangeF * v.vertex.x*_Downward; v.vertex = mul(rotate,v.vertex); v.vertex += float4(-5,0,0,0); o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); return o; } fixed4 frag(v2f i):COLOR { fixed4 color = tex2D(_MainTex,-i.uv); return _Color * color; } ENDCG } pass { Cull Front CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; }; fixed4 _Color; float _Angle; float _Warp; float _Downward; float _WarpPos; sampler2D _SecTex; float4 _MainTex_ST; v2f vert(appdata_base v) { v2f o; v.vertex += float4(5,0,0,0); float s; float c; sincos(radians(-_Angle),s,c); float4x4 rotate={ c,s,0,0, -s,c,0,0, 0,0,1,0, 0,0,0,1}; float rangeF=saturate(1 - abs(90-_Angle)/90); v.vertex.y += -_Warp*sin(v.vertex.x*0.4-_WarpPos* v.vertex.x)*rangeF; v.vertex.x -= rangeF * v.vertex.x*_Downward; v.vertex = mul(rotate,v.vertex); v.vertex += float4(-5,0,0,0); o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); return o; } fixed4 frag(v2f i):COLOR { float2 uv = i.uv; uv.x = -uv.x; fixed4 color = tex2D(_SecTex,-uv); return _Color * color; } ENDCG } } }
动态修改这个值就可以达到Plan的翻转
下面我们实现翻书效果
我们接下来要用DOTween,不明白DOTween可百度下来了解使用这里就不详解;
创建Resources文件夹 在内创建子文件夹FrontTextur(正面)和VersoTextur(反面)用来存放一本书的正反面图片 把自己准备的图片导入 为了方面动态加载我都用数字代替第几页
接下来我们创建一个Plan位置归零
创建材质球PageTurning2
然后再复制一个改名PageTurning3
把刚才创建的Plan添加材质球PageTurning3
然后将Plan作为预设拖入Resources。
删除Plan,然后重新创建一个Plan添加材质球PageTurning2。
接下来用下面代码实现翻书
using UnityEngine; using DG.Tweening; public class PageTurning : MonoBehaviour { private Material m_Material; private int nowPage = 1; //最下面页码 private int lastPage; //已经翻过的 private int allPage = 10; //所有的页数 private float Thickness = 0; //书的厚度 void Start () { m_Material = GetComponent<MeshRenderer>().material; Texture ShowFront = Resources.Load("AllTextur/FrontTextur/" + nowPage.ToString(), typeof(Texture)) as Texture; Texture ShowVerso = Resources.Load("AllTextur/VersoTextur/" + nowPage.ToString(), typeof(Texture)) as Texture; m_Material.SetTexture("_MainTex", ShowFront); m_Material.SetTexture("_SecTex", ShowVerso); } public void Turning() { nowPage += 1; if (nowPage>10) //设置阈值 { nowPage = 1; } lastPage = nowPage - 1; if (lastPage < 1) { lastPage = allPage; } #region 翻动的页面 Material m_Material2 = (Instantiate(Resources.Load("Plane"),new Vector3(0, Thickness+=0.001f, 0), Quaternion.identity) as GameObject).GetComponent<MeshRenderer>().material; m_Material2.SetFloat("_Angle", 0); //DoTween做旋转动画 m_Material2.DOFloat(180, "_Angle", 2); //m_Material2.name = "当前Material"+ lastPage; Texture ShowFrontLast = Resources.Load("AllTextur/FrontTextur/" + lastPage.ToString(), typeof(Texture)) as Texture; //Resources加载正面图片 Texture ShowVersoLast = Resources.Load("AllTextur/VersoTextur/" + lastPage.ToString(), typeof(Texture)) as Texture; //Resources加载反面图片 m_Material2.SetTexture("_MainTex", ShowFrontLast); //更改材质的正面 m_Material2.SetTexture("_SecTex", ShowVersoLast); //更改材质球的反面 #endregion Texture ShowFront = Resources.Load("AllTextur/FrontTextur/" + nowPage.ToString(), typeof(Texture)) as Texture; //Resources加载正面图片 Texture ShowVerso = Resources.Load("AllTextur/VersoTextur/" + nowPage.ToString(), typeof(Texture)) as Texture; //Resources加载反面图片 m_Material.SetTexture("_MainTex", ShowFront); //更改材质求的正面 m_Material.SetTexture("_SecTex", ShowVerso); //更改材质球的反面 //m_Material.name = "当前Material"+nowPage.ToString(); } }
把这个代码挂载到刚创建的Plan上
创建一个 UI的Button绑定脚本PageTurning上的 Turning方法。这样就实现了翻书的效果。
现在只做了往后翻书效果,如果想做往前翻的效果可把每次创建的Plan加载到集合中然后从集合中修改他们的材质球
m_Material.SetFloat("_Angle", value)
加载全部内容