Unity3D实现纹理旋转的三种方法

发表于2018-10-30
评论0 9.7k浏览
纹理旋转在项目的开发中经常会需要用到,为此这篇文章给大家分享下三种实现纹理旋转的方法。

方法一:

纹理旋转实现思路:纹理坐标*平移矩阵*旋转矩阵(类似顶点旋转);

矩阵一般要求中心点为(0,0) 而纹理中心点默认(0.5,0.5);所以先得平移到(0,0);可以考虑乘以平移矩阵[1,0,0,0,1,0,-0.5,-0.5,1]

也可以直接简化 (texcoord.x-0.5,texcoord.y-0.5)。

纹理坐标二维坐标 旋转矩阵为[cosA,sinA,-sinA,cosA]; 旋转结果:mul(平移后纹理坐标,旋转矩阵) //注意 u3d中mul函数,我用的不好使,我直接用后面的公式算的;旋转后的纹理坐标=(cosA(x-0.5)-sinA(y-0.5),sinA(x-0.5)+cosA(y-0.5));

因为纹理坐标范围[0,1] 所以需要把旋转好的纹理在平移回来;旋转好的纹理坐标+float2(0.5)=最终输出纹理;

如果实现纹理移动 需要TRANSFORM_TEX(最终输出纹理, _MainTex);

方法二:代码实现

主要通过 MeshFilter.mesh.SetUVs函数来实现uv旋转,主要代码如下:
    public void RotateUV ()
    {
        List<Vector2> uvs = new List<Vector2>( go.GetComponent<MeshFilter>().mesh.uv );
        float speed = 0;
        if ( switchfun )
            speed = rotatespeed * Mathf.Deg2Rad * Time.deltaTime;
        else
            speed = rotatespeed * Mathf.Deg2Rad;
        for ( int i = 0; i < uvs.Count; i++ )
        {
            Vector2 uv = uvs[i] - new Vector2( 0.5f, 0.5f );
            uv = new Vector2( uv.x * Mathf.Cos( speed ) - uv.y * Mathf.Sin( speed ),
                              uv.x * Mathf.Sin( speed ) + uv.y * Mathf.Cos( speed ) );
            uv += new Vector2( 0.5f, 0.5f );
            uvs[i] = uv;
        }
        go.GetComponent<MeshFilter>().mesh.SetUVs( 0, uvs );
    }

方法三:用shader实现
Shader "Custom/RotateShader" {       
       Properties
       {
           _MainTex("Main Tex",2D)="Write"{}
           //给unity3d提供一个滑动条来控制旋转速度
           _RotateSpeed("Rotate Speed",Range(0,10))=5
       }
       SubShader
       {
         Tags{"Queue"="Transparent" "RenderType"="Transparent"}
         Blend SrcAlpha OneMinusSrcAlpha
         Pass
         {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            sampler2D _MainTex;
            float _RotateSpeed;
            struct v2f
            {
               float4 pos:POSITION;
               float4 uv:TEXCOORD;
            };
            v2f vert(appdata_base v)
            {
               v2f o;
               o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
               o.uv=v.texcoord;
               return o;
            }
            half4 frag(v2f i):COLOR
            {  //定义一个float2来存储顶点的UV的XY,减去0.5是因为uv旋转的起始是1,1为中心,XY都减去0.5是把中心点移到中心。
               float2 uv=i.uv.xy -float2(0.5,0.5);
              //        _Time   是一个内置的float4时间,X是1/20,Y是1倍,Z是2倍,W是3倍           
              //        旋转矩阵的公式是: COS() -  sin() , sin() + cos()     顺时针
              //                                             COS() +  sin() , sin() - cos()     逆时针     
               uv = float2(    uv.x*cos(_RotateSpeed * _Time.y) - uv.y*sin(_RotateSpeed*_Time.y),
                                      uv.x*sin(_RotateSpeed * _Time.y) + uv.y*cos(_RotateSpeed*_Time.y) );
               //再加回来
               uv += float2(0.5,0.5);
               half4 c=tex2D(_MainTex,uv);
               return c;
            }
            ENDCG        
         }                  
     }
} 
旋转后发现,四个顶点周围不太正确,哪是因为UNITY3D默认采取了 重叠纹理寻址模式,需要再贴图里改为夹取纹理寻址模式,贴图的 wrap Mode改为clamp。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: