UnityShader_用Plane实现翻书效果

之前在网上看到一个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)

猜你喜欢

转载自blog.csdn.net/qq_39741605/article/details/80678229