原创作品

Unity特效(2) 图片切割

罗培羽 发表于   2021-09-29 14:22:07
1610
0
5

游戏开发中,常常把多张图片素材合并成图集,然后程序读取所需的部分显示。如下展示的是一张人物行走图,程序需要把它切分成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);
}
}
}

没有标签
确定
评论(0)
还没有人评论,快来抢沙发吧!
  • 咨询
    客服
  • 扫码加入QQ群 或搜索QQ群号: 797421367
  • 扫码关注公众号 或微信搜索: cokey游戏特效