【Unity Shaders】Using Textures for Effects——让sprite sheets动起来
本系列主要参考《Unity Shaders and Effects
Cookbook》一书(感谢原书作者),同时会加上一点个人理解或拓展。
这里是本书所有的插图。这里是本书所需的代码和资源(当然你也可以从官网下载)。
========================================== 分割线 ==========================================
题外话
好久未更新,一些习惯还是应该要好好坚持啊。最近发现Android上一个很好的应用,希望每天可以坚持看一个视频,了解下最新的科技动态和演讲,也推荐给大家使用!
这次内容主要讲如何使用sprite sheets制作2D动画。在Unity中,实际上已经有很多插件可以完成这个工作,例如2dTookit,新版的Unity中支持2D应该也会提供类似的功能了。虽然如此,我还是希望通过这篇文章可以更深入地理解2D动画的原理。说到动画的原理,先要提到一个名词,sprite atlas,也可以称为image sequence,实际上就是一张大图中包含了很多张小图,如下:
当我们按照一定速率滚动这张图时,就会发现图片动起来了,这我们应该都有经验,以前看小人书快速翻动时就发现小人在动。这里实际上也是这个原理。
准备工作
- 准备一张sprite sheet,你可以自己画一张也可以从网上下载一张,或是直接使用本书资源。这张图不需要太复杂,只需要包含一组图片序列来供滚动浏览就行。下面是本书中的实例图片(5084_Code/Unity assets/5084_02_UnityAssets/Textures/Chapter02_SpriteSheet005.png):
- 创建一个新的Shader和一个新的Material,名称分别为AnimateSprites;
- 新建一个场景,名为AnimateSprites_Scene,在场景中添加平行光,创建一个新的平面,并把上一步中的Material设为其材质,将第一步中的图片拖到Material的图片上。最后如下所示:
实现
- 打开Shader编辑器,向Properties 区域添加三个新的Properties:
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {} // Create the properties below
_TexWidth ("Sheet Width", float) = 0.0
_CellAmount ("Cell Amount", float) = 0.0
_Speed ("Speed", Range(0.01, 32)) = 12
} - 在SubShader区域为每个新增的Properties增加对应的引用,以便在代码中使用它们的值:
CGPROGRAM
#pragma surface surf Lambert sampler2D _MainTex; //Create the connection to the properties inside of the
//CG program
float _TexWidth;
float _CellAmount;
float _Speed;下面更改surf函数。
- 将_MainTex的UV坐标先存储到单独的变量中:
//Lets store our UVs in a seperate variable
float2 spriteUV = IN.uv_MainTex;之后,我们将使用该变量计算新的UV坐标。
- 下面,我们需要计算每个小图的宽度,最后计算得到每个小图宽度占整体的百分比。
原书中代码如下://Lets calculate the width of a singe cell in our
//sprite sheet and get a uv percentage that each cel takes up.
float cellPixelWidth = _TexWidth/_CellAmount;
float cellUVPercentage = cellPixelWidth/_TexWidth;但通过观察代码可以发现,缩短为一行即可:
//Lets calculate the width of a singe cell in our
//sprite sheet and get a uv percentage that each cel takes up.
float cellUVPercentage = 1.0/_CellAmount;对于示例图片,其宽度为512,包含了9张小图,Inspector中配置如下:
- 下面,通过得到系统时间来计算需要在原图上的偏移量,来得到不同的小图:
//Lets get a stair step value out of time so we can increment
//the uv offset
float timeVal = fmod(_Time.y * _Speed, _CellAmount);
timeVal = ceil(timeVal); - 最后,计算在X方向上的最终偏移量。
原书中代码如下://Animate the uv's forward by the width precentage of
//each cell
float xValue = spriteUV.x;
xValue += cellUVPercentage * timeVal * _CellAmount;
xValue *= cellUVPercentage;同样,观察cellUVPercentage的计算式,可以简化上述代码如下:
//Animate the uv's forward by the width precentage of
//each cell
float xValue = spriteUV.x;
xValue += timeVal;
xValue *= cellUVPercentage; - 应用最终偏移量,显示到plane上:
spriteUV = float2(xValue, spriteUV.y); half4 c = tex2D (_MainTex, spriteUV);
o.Albedo = c.rgb;
o.Alpha = c.a;
Shader "Custom/AnimateSprites" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
// Create the properties below
_TexWidth ("Sheet Width", float) = 0.0
_CellAmount ("Cell Amount", float) = 0.0
_Speed ("Speed", Range(0.01, 32)) = 12
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
//Create the connection to the properties inside of the
//CG program
float _TexWidth;
float _CellAmount;
float _Speed;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
//Lets store our UVs in a seperate variable
float2 spriteUV = IN.uv_MainTex;
//Lets calculate the width of a singe cell in our
//sprite sheet and get a uv percentage that each cel takes up.
float cellUVPercentage = 1.0/_CellAmount;
//Lets get a stair step value out of time so we can increment
//the uv offset
float timeVal = fmod(_Time.y * _Speed, _CellAmount);
timeVal = ceil(timeVal);
//Animate the uv's forward by the width precentage of
//each cell
float xValue = spriteUV.x;
xValue += timeVal;
xValue *= cellUVPercentage;
spriteUV = float2(xValue, spriteUV.y);
half4 c = tex2D (_MainTex, spriteUV);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
解释
float cellUVPercentage = 1.0/_CellAmount;
float timeVal = fmod(_Time.y * _Speed, _CellAmount);
timeVal = ceil(timeVal);
float xValue = spriteUV.x;
xValue += timeVal;
xValue *= cellUVPercentage;
第一行首先声明一个新的变量xValue,用于存储用于图片采样的x坐标。它首先被初始为surf函数的输入参数In的横坐标。类型为Input的输入参数In代表输入的texture的UV坐标,范围为0到1。第二行向原值加上小图的整数偏移量,最后为了只显示一张小图,我们还需将x值乘以小图所占百分比cellUVPercentage。
+ 1) * 0.11 = 0.11至(1 + 1) * 0.11 = 0.22,即第二张小图对应的贴图范围。这样就按照顺序显示小图,从而让整个画面动起来了。
扩展
Shader "Custom/AnimateSprites" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
// Create the properties below
_CellAmount ("Cell Amount", float) = 0.0
_TimeValue ("Time Value", float) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
//Create the connection to the properties inside of the
//CG program
float _CellAmount;
float _TimeValue;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
//Lets store our UVs in a seperate variable
float2 spriteUV = IN.uv_MainTex;
//Lets calculate the width of a singe cell in our
//sprite sheet and get a uv percentage that each cel takes up.
float cellUVPercentage = 1.0/_CellAmount;
//Animate the uv's forward by the width precentage of
//each cell
float xValue = spriteUV.x;
xValue += _TimeValue;
xValue *= cellUVPercentage;
spriteUV = float2(xValue, spriteUV.y);
half4 c = tex2D (_MainTex, spriteUV);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
C#代码如下:
using UnityEngine;
using System.Collections; public class SpriteAnimator : MonoBehaviour
{ public float speed = 5.0f;
public int cellAmount = 0; float timeValue = 0.0f; void Start ()
{
transform.renderer.material.SetFloat("_CellAmount", cellAmount);
} // Update is called once per frame
void FixedUpdate ()
{
timeValue = Mathf.Ceil(Time.time * speed % 9);
transform.renderer.material.SetFloat("_TimeValue", timeValue);
}
}
在Inspector界面上,我们只需要调整C#代码的两个变量即可,而不需要更改Material的变量。这样,我们将计算整数偏移量的工作转移到了C#代码中。
【Unity Shaders】Using Textures for Effects——让sprite sheets动起来的更多相关文章
- 【Unity Shaders】Using Textures for Effects介绍
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Using Textures for Effects —— 实现Photoshop的色阶效果
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Using Textures for Effects——打包和混合textures
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Using Textures for Effects——通过修改UV坐标来滚动textures
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】使用Unity Render Textures实现画面特效——画面特效中的亮度、饱和度和对照度
本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...
- 【Unity Shaders】《Unity Shaders and Effects Cookbook》总结篇
我的唠叨 不知不觉,从发表第一篇关于<Unity Shaders and Effects Cookbook>已经快十个月了.一开始的初衷就是学习笔记,毕竟将来回过头去看的时候,再看英文难免 ...
- 【Unity Shaders】使用Unity Render Textures实现画面特效——建立画面特效脚本系统
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Lighting Models —— 衣服着色器
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Reflecting Your World —— Unity3D中的遮罩反射(Masking Reflections)
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
随机推荐
- Laravel中构造方法中不能写return!!!
今天遇到的大坑 在laravel中 __construct 这个方法中不能写return 完全不能返回 而且还会向下执行具体原因不知道为什么解决办法!!!!用中间件来实现就可以了 Over!!!
- js模拟form表单提交数据, js模拟a标签点击跳转,避开使用window.open引起来的浏览器阻止问题
js模拟form表单提交数据, js模拟a标签点击跳转,避开使用window.open引起来的浏览器阻止问题 js模拟form表单提交数据源码: /** * js模拟form表单提交 * @param ...
- 小白到大神,Python 密集知识点汇总
Python 基础 1. 变量 你可以把变量想象成一个用来存储值的单词.我们看个例子. Python 中定义一个变量并为它赋值是很容易的.假如你想存储数字 1 到变量 "one" ...
- Android简易实战教程--第三十九话《简单的模糊查询》
今天这一篇小案例模拟模糊查询,即输入一个字符,显示手机对应的所有存在该字符的路径. 布局: <?xml version="1.0" encoding="utf-8& ...
- Cocos2D-ObjC:在RPG游戏中混合Swift代码
我之前写过一个RPG游戏<<熊猫之魂 SoulOfPanda>> 编译器使用的是SpriteBuilder,很好很强大!全部代码都由Objc完成,现在想尝试一下在其中混入Swi ...
- MongoDb 用 mapreduce 统计留存率
MongoDb 用 mapreduce 统计留存率(金庆的专栏)留存的定义采用的是新增账号第X日:某日新增的账号中,在新增日后第X日有登录行为记为留存 输出如下:(类同友盟的留存率显示)留存用户注册时 ...
- Memcached - Base
Memcached 标签 : Java与NoSQL 在程序的实现中, 经常会忽略程序的运行时间. 即使采用类似的实现方法, 有时候运行速度也会相差很多. 大多数情况下, 这一速度上的差异是由数据访问速 ...
- 关于JQuery中的ajax请求或者post请求的回调方法中的操作执行或者变量修改没反映的问题
前段时间做一个项目,而项目中所有的请求都要用jquery 中的ajax请求或者post请求,但是开始处理一些简单操作还好,但是自己写了一些验证就出现问题了,比如表单提交的时候,要验证帐号的唯一性,所以 ...
- Java进阶(四十二)Java中多线程使用匿名内部类的方式进行创建3种方式
Java中多线程使用匿名内部类的方式进行创建3种方式 package cn.edu.ujn.demo; // 匿名内部类的格式: public class ThreadDemo { public st ...
- Apache commons email 使用过程中遇到的问题
apache-commons-email是对mail的一个封装,所以使用起来确实是很方便.特别的,官网上的tutorial也是极其的简单.但是我也仍然是遇到了没有解决的问题. jar包的添加 mail ...