Unity特效设计教程:图片的切割与翻转

作者:罗培羽 2019-01-16


一、图片切割

游戏开发中,常常把多张图片素材合并成图集,然后程序读取所需的部分显示。如下展示的是一张人物行走图,程序需要把它切分成12张小图加以显示。一种做法是使用Sprite Editor切分图集,当做多张小图来处理。如果Image能够只显示图集的一部分,程序还是把图集当做1张图片处理,可以减少不小工作量。本文提供一种使用shader实现上述功能的例子。



1、编写Shader
下面的着色器代码使用了顶点/片元着色器处理图片切割功能。这里定义5个属性,其中_MainTex代表图片贴图,_ColCount和_RowCount代表图片的列数和行数,_ColIndex和_RowIndex表示要显示哪一行哪一列的图片。

核心代码是“o.uv.x = (_ColIndex + v.texcoord.x)/_ColCount”和“o.uv.y = (_RowIndex + v.texcoord.y)/_RowCount”,它们实现了UV坐标的变换。“o.uv.x = (_ColIndex + v.texcoord.x)/_ColCount”即是“o.uv.x = _ColIndex*(1/_ColCount) + v.texcoord.x *(1/_ColCount)”的化简式,由于纹理坐标被归一化到[0,1]的范围,1/_ColCount即表示每一张小图的宽度。

Shader "Lpy/ImageClip"
{
        Properties
        {
                _MainTex ("Main Tex", 2D) = "white" {}
            _ColCount ("Column Count", int) = 4
            _RowCount ("Row Count", int) = 4
            _ColIndex ("Col Index", int) = 0
            _RowIndex ("Row Index", int) = 0
        }
        
        SubShader
        {
                Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
               
                Pass
                {
                        Tags { "LightMode"="ForwardBase" }
                        ZTest off
                        ZWrite Off
                        Blend SrcAlpha OneMinusSrcAlpha
                        
                        CGPROGRAM
                        #pragma vertex vert  
                        #pragma fragment frag
                        #include "UnityCG.cginc"
               
                        sampler2D _MainTex;
                        int _ColCount;
                        int _RowCount;
                        int _ColIndex;
                        int _RowIndex;
                          
                        struct a2v
                        {  
                            float4 vertex : POSITION;
                            float2 texcoord : TEXCOORD0;
                        };  
                        
                        struct v2f
                        {  
                            float4 pos : SV_POSITION;
                            float2 uv : TEXCOORD0;
                        };  
                        
                        v2f vert (a2v v)
                        {  
                                v2f o;  
                                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
                                
                                o.uv.x = (_ColIndex + v.texcoord.x)/_ColCount;
                                o.uv.y = (_RowIndex + v.texcoord.y)/_RowCount;
                                return o;
                        }  
                        
                        fixed4 frag (v2f i) : SV_Target
                        {
                                fixed4 c = tex2D(_MainTex, i.uv);
                                return c;
                        }
                        ENDCG
                }  
        }
        FallBack "Transparent/VertexLit"
}

2、使用材质

新建一个名为ImageClip的材质,选择上述编写的shader。将ColumnCount和RowCount设置为图集的列数和行数,如下图所示。


将刚创建的材质应用于图片上,如下图所示。


在Scene或Game视图中观察图片,改变材质的ColIndex和RowIndex属性,即可显示不同的小图。如下图所示。

3、代码控制

如下代码展示使用脚本控制材质属性的方法,当按下空格键时,改变材质的RowIndex属性,展现不同小图。

using UnityEngine;
using System.Collections;
using UnityEngine.UI;


public class RoleCtrl : MonoBehaviour
{
        public Image image;
        private Material mtl;
        // Use this for initialization
        void Start ()
        {
                mtl = image.material;
        }
        
        // Update is called once per frame
        void Update ()
        {
                if (Input.GetKeyDown (KeyCode.Space))
                {
                        int row = mtl.GetInt("_RowIndex");


                        row++;
                        if(row >= 4)
                                row = 0;


                        mtl.SetInt("_RowIndex", row);
                }
        }
}

二、图片翻转
2D游戏开发中,往往会使用翻转的图片(如下图),然而Transform的旋转并不能完成这一功能,那么什么办法将图片翻转呢?



1、编写Shader

下面的着色器代码使用了顶点/片元着色器处理图片翻转功能。这里定义3个属性,其中_MainTex代表图片贴图,_Hor代表是否启用水平翻转,_Ver代表是否启用垂直翻转。核心代码是“o.uv.x = (1-v.texcoord.x)*_Hor + v.texcoord.x*(1-_Hor)”和“o.uv.y = (1-v.texcoord.y)*_Ver + v.texcoord.y*(1-_Ver);”它们实现了UV坐标的变换。在o.uv.x的计算式中,如果_Hor为0,那么“o.uv.x = v.texcoord.x”即为原始UV,如果_Hor为1,由于纹理坐标被归一化到[0,1]的范围,那么“o.uv.x = 1-v.texcoord.x”即为翻转后的UV。

Shader "Lpy/ImageFlip"
{
        Properties
        {
                _MainTex ("Main Tex", 2D) = "white" {}
               
            _Hor ("Is Horizontal Filp", Range (0, 1)) = 0
            _Ver ("Is Vertical Filp", Range (0, 1)) = 0
        }
        
        SubShader
        {
                Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
               
                Pass
                {
                        Tags { "LightMode"="ForwardBase" }
                        ZTest off
                        ZWrite Off
                        Blend SrcAlpha OneMinusSrcAlpha
                        
                        CGPROGRAM
                        #pragma vertex vert  
                        #pragma fragment frag
                        #include "UnityCG.cginc"
               
                        sampler2D _MainTex;
                        int _Hor;
                        int _Ver;
                          
                        struct a2v
                        {  
                            float4 vertex : POSITION;
                            float2 texcoord : TEXCOORD0;
                        };  
                        
                        struct v2f
                        {  
                            float4 pos : SV_POSITION;
                            float2 uv : TEXCOORD0;
                        };  
                        
                        v2f vert (a2v v)
                        {  
                                v2f o;  
                                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
                                
                                o.uv.x = (1-v.texcoord.x)*_Hor + v.texcoord.x*(1-_Hor);
                                o.uv.y = (1-v.texcoord.y)*_Ver + v.texcoord.y*(1-_Ver);
                                return o;
                        }  
                        
                        fixed4 frag (v2f i) : SV_Target
                        {
                                fixed4 c = tex2D(_MainTex, i.uv);
                                return c;
                        }
                        ENDCG
                }  
        }
        FallBack "Transparent/VertexLit"
}

2、使用材质

新建一个名为ImageFilp的材质,选择上述编写的shader,设置Is Horizontal Filp和Is Vertical Filp,如下图所示。



将刚创建的材质应用于图片上,即可看到翻转的效果。如下图所示。



最后依然到了广告时间:笔者即将出版的一本Unity3D实战类书籍《Unity3D网络游戏实战》。该书通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。相信透过本书,读者能够掌握Unity3D网络游戏开发的大部分知识,也能够从框架设计中了解商业游戏的设计思路,感谢大家支持。

知乎专栏:https://zhuanlan.zhihu.com/p/24739023


最新评论
暂无评论
参与评论

商务合作 查看更多

编辑推荐 查看更多