Vertex and fragment shader 14 - 2D過場淡入淡出(Fade in/out) - 翻頁效果(斜角)

  水平的翻頁效果似乎有點單調,於是就想說做的三角形的好了,稍微花了點時間做了個計算,不過效果似乎還可以。

呈現的效果大概是如此。


--
實作測試(滑鼠左鍵點擊場景)


--
Metrix旋轉的公式(詳細內容請參考http://en.wikipedia.org/wiki/Rotation_matrix)
逆時針

順時針


  所以基本上先計算出θ角度,接著再做旋轉計算,以求得翻頁折角那個部分的材質旋轉後的Matrix,所以θ角度就用簡單的三角函數運算,因為已經有直角三角形的兩邊長,所以直接用atan(y/x)來取得θ角。
  已經有θ角了之後就可以用上面的公式來計算,這邊是順時針旋轉所以使用第二個公式:
float2x2 rotationMatrix = float2x2( cos, sin, -sin, cos); ,而因為我需要轉到折角的位置,所以事實上是要轉兩倍的θ角。



  計算完並且翻轉過後就是到時候要做為折角使用的座標,接著就使用簡單的判別式就好,有原點的座標同時也有兩個端點的座標,就可以由 y=ax+b 得到兩條線段,然後只要是在這兩線段夾的範圍內,就把材質轉換為剛剛逆轉的材質。
float invert = (_AmountY-(1-newTip.y))/abs(_AmountY-(1-newTip.y));
if(pos.y-pos.x*((newTip.y-(1-_AmountY))/newTip.x) > 0 && invert*(pos.y-pos.x*(newTip.y/(newTip.x-(1-_AmountX)))) > 0)
    texColor = invertTexColor;

  最後只有這樣的話還有點小問題,右上角會沒有缺口,所以直接把右上角的部分切掉就好了。
float2 newHypotenuse = float2((coord.x-_AmountX)/(1-_AmountX), (coord.y-_AmountY)/(1-_AmountY));
clip ((1-newHypotenuse.y)-newHypotenuse.x);


  到這邊就完成了,之後只要調整AmountX跟AmountY來調整折的位置就好,同時使用Color跟Colo2來改變前後的顏色,避免顏色類似看不出差異。


完整Shader Code
Shader "Custom/NewShader" 
{
   Properties
   {
      _MainTex ("Base (RGB)", 2D) = "white" {}
      _Color ("Color", Color) = (1,1,1,1)
      _Color2 ("Color 2", Color) = (1,1,1,1)
      _AmountX ("Amount X", Range (-1,1)) = 0
      _AmountY ("Amount Y", Range (-1,1)) = 0
   }
   
   SubShader {
      Pass {
         Cull Off
         Lighting Off
         Blend SrcAlpha OneMinusSrcAlpha
         CGPROGRAM
         
         #pragma vertex vert
         #pragma fragment frag
         #pragma target 3.0
         
         uniform sampler2D _MainTex;
         uniform float _AmountX;
         uniform float _AmountY;
         uniform float4 _Color;
         uniform float4 _Color2;
   
         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float2 uv : TEXCOORD0;
            float2 rotateUV : TEXCOORD1;
            float2 tipPos : TEXCOORD2;
         };

         vertexOutput vert(vertexInput input)
         {
            vertexOutput output;

            output.uv = input.texcoord;
            output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
            
            float hypotenuse = length(float2(1-_AmountX,1-_AmountY));
            float theta = atan((1-_AmountY)/(1-_AmountX));
            float h = ((1-_AmountX)*(1-_AmountY))/hypotenuse;
            output.tipPos = float2(h*2*sin(theta), h*2*cos(theta));

            float s = sin ( theta*2 );
            float c = cos ( theta*2 );
            float2x2 rotationMatrix = float2x2( c, s, -s, c);
            float2 invertInput = float2(output.uv.x-(1-output.tipPos.x), output.uv.y-(1-output.tipPos.y));
            float2 rotateUV = mul( invertInput, rotationMatrix );
            rotateUV.y = -rotateUV.y;
            output.rotateUV = rotateUV;

            return output;
         }

         half4 frag(vertexOutput input) : COLOR
         {
             float4 texColor = tex2D(_MainTex, input.uv) * _Color;
             float4 invertTexColor = tex2D(_MainTex, input.rotateUV) * _Color2;
             float2 coord = input.uv.xy;
             float2 newTip = input.tipPos;

             float2 pos = float2(coord.x-(1-newTip.x), coord.y-(1-newTip.y));
             float invert = (_AmountY-(1-newTip.y))/abs(_AmountY-(1-newTip.y));
             if(pos.y-pos.x*((newTip.y-(1-_AmountY))/newTip.x) > 0 && invert*(pos.y-pos.x*(newTip.y/(newTip.x-(1-_AmountX)))) > 0)
                 texColor = invertTexColor;

             float2 newHypotenuse = float2((coord.x-_AmountX)/(1-_AmountX), (coord.y-_AmountY)/(1-_AmountY));
             clip ((1-newHypotenuse.y)-newHypotenuse.x);

             return texColor;
         }
         ENDCG
      }
   }
   Fallback "Diffuse"
}

2014/4/16 22:07 修個小bug,漏掉幾個字
如果有任何想法歡迎提出。

No comments:

Post a Comment