[UnityShaderCookbook 读书笔记] [03] UV 动画

5 篇文章 0 订阅
4 篇文章 0 订阅

使用纹理,能够迅速让 Shader 取得非常好的效果
同时,也需要注意纹理的数量,因为它会给系统带来较大的负担,尤其是在手机上需要将纹理控制在最小,这样才能保证游戏运行的流畅性

有关于二维纹理如何映射到三维表面,参考这里
http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter03.html


UV 滚轴动画


使用 UV 动画来实现让贴图随着时间沿着 u,v 两个方向移动
它的实现原理就是,用Unity为我们提供的系统时间乘以自定义的速度属性,作为 UV 坐标的索引值从贴图中取值,实现 UV 滚轴动画。

UV 滚轴动画的原理图解
这里写图片描述

我们需要先在属性段里添加两个float属性,分别用于控制 UV 动画两个方向的速度

Properties
{
     _MainTex ("Base (RGB)", 2D) = "white" {}
     _ScrollXSpeed ("X Scroll Speed", Range(0, 10)) = 2
     _ScrollYSpeed ("Y Scroll Speed", Range(0, 10)) = 2
}

在SubShader块内的 CGPROGRAM 内再次声明这两个变量,
#pragma surface surf Lambert 后添加

fixed _ScrollXSpeed;
fixed _ScrollYSpeed;

再修改 surface 函数,将传递给 tex2D函数(用于进行纹理采样)的UV值随着时间进行变换。
我们使用内建的 _Time 变量来实现 UV 动画,当编辑器中 Play 按钮被按下时,_Time 会开始走动。

对于更多的内建参数,参考
http://docs.unity3d.com/Documentation/Components/SL-BuiltinValues.html

将 surface 函数修改为

void surf (Input IN, inout SurfaceOutput o)
{
     //创建一个变量存储当前输入的UV值
     fixed2 scrolledUV = IN.uv_MainTex;

     //分别存储x, y 两个方向的速度
     fixed xScrollValue = _ScrollXSpeed * _Time;
     fixed yScrollValue = _ScrollYSpeed * _Time;

     //将 UV 偏移应用于之前建立的变量
     scrolledUV += fixed2(xScrollValue, yScrollValue);

     //应用动画化的UV值从纹理中获取颜色值,并传递给output
     half4 c = tex2D (_MainTex, scrolledUV);
     o.Albedo = c.rgb;
     o.Alpha = c.a;
}

最终实现的动画效果为
------------------------------图------------------------------

最终的 UV 动画 Shader 为

Shader "HineNotes/CookbookCh_02/AnimatedUV" {
     Properties {
          _MainTex ("Base (RGB)", 2D) = "white" {}
          _ScrollXSpeed ("X Scroll Speed", Range(0, 10)) = 2
          _ScrollYSpeed ("Y Scroll Speed", Range(0, 10)) = 2
     }
     SubShader {
          Tags { "RenderType"="Opaque" }
          LOD 200

          CGPROGRAM
          #pragma surface surf Lambert

          fixed _ScrollXSpeed;
          fixed _ScrollYSpeed;

          sampler2D _MainTex;

          struct Input {
               float2 uv_MainTex;
          };

          void surf (Input IN, inout SurfaceOutput o) {
               fixed2 scrolledUV = IN.uv_MainTex;

               fixed xScrollValue = _ScrollXSpeed * _Time;
               fixed yScrollValue = _ScrollYSpeed * _Time;

               scrolledUV += fixed2(xScrollValue, yScrollValue);
               half4 c = tex2D (_MainTex, scrolledUV);
               o.Albedo = c.rgb;
               o.Alpha = c.a;
          }
          ENDCG
     }
     FallBack "Diffuse"
}

UV Sprite Sheets 动画


UV Sprite Sheets 动画方式,实际是将许多大小相等的序列帧以矩阵方式排列到一张贴图上,shader 按照时间顺序逐帧读取对应的像素块并播放出来,形成了序列帧动画。
UV Sprite Sheets 要怎么翻译呢? UV 精灵表单?—呵呵,好调皮的名字啊 = =b 所以还是用英文吧

如下图,是我们要用到的二维 UV Sprite Sheets
这里写图片描述

UV Sprite Sheets 原理图解
这里写图片描述

注:以下的实现方式与原书中略有不同,去掉了不必要的参数,并将读取的 sheet 从一维扩展到了二维

在 Shader 的属性段中添加属性

Properties
{
     _MainTex ("Base (RGB)", 2D) = "white" {}

     _CellAmountRow ("Cell Amount Row", float) = 0.0     // 单元格行数
     _CellAmountCol ("Cell Amount Column", float) = 0.0  // 单元格列数
     _Speed ("Speed", Range( 0.01, 32 )) = 12     // 播放速度
}

这里写图片描述

再修改 Surface 函数
// 先将输入的 UV 值存储起来
float2 spriteUV = IN.uv_MainTex;

根据单元格的行列数目来计算得到单个单元格在横向和纵向的百分比
float cellUVPercentageX = 1/_CellAmountCol;
float cellUVPercentageY = 1/_CellAmountRow;

行乘以列,得到总共的单元数目
float cellAmount = _CellAmountRow * _CellAmountCol;

利用 Unity Shader 的内建变量 _Time 来得到一个随着时间递增的值
float timeVal = fmod ( _Time.y * _Speed, _CellAmount);
timeVal = ceil (timeVal);

计算 x 方向的偏移值
spriteUV.x += int(fmod(timeVal,_CellAmountCol));

计算 y 方向的偏移值
spriteUV.y += int(timeVal/_CellAmountCol);

最后乘以百分比将其缩放
spriteUV.x *= cellUVPercentageX;
spriteUV.y *= cellUVPercentageY;

传递最终输出值
half4 c = tex2D (_MainTex, spriteUV);
o.Albedo = c.rgb;
o.Alpha = c.a;

使用 CGFX 中的内建函数 fmod()

函数描述
fmod(x,y)返回 x / y 的余数,与 x 同号。如果 y 为 0, 结果由解释器定义决定。

使用 CGFX 中的内建函数 ceil()

函数描述
ceil(x)返回不小于 x 的最大整数

最终实现的动画效果为
这里写图片描述

最终的 UV Sprite Sheet Shader 代码为

Shader "HineNotes/CookbookCh_02/UVSpreiteSheet"
{
     Properties
     {
          _MainTex ("Base (RGB)", 2D) = "white" {}

          //Create the properties below
          _CellAmountRow ("Cell Amount Row", float) = 0.0
          _CellAmountCol ("Cell Amount Column", 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 _CellAmountRow;
          float _CellAmountCol;
          float _Speed;

          struct Input
          {
               float2 uv_MainTex;
          };

          void surf (Input IN, inout SurfaceOutput o)
          {

               // store UVs in a seperate variable
               float2 spriteUV = IN.uv_MainTex;

               // calculate percentage of x
               float cellUVPercentageX = 1/_CellAmountCol;
               // calculate percentage of y
               float cellUVPercentageY = 1/_CellAmountRow;
               // calculate the amount of cells
               float cellAmount = _CellAmountRow * _CellAmountCol;

               // 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);

               // calculate x offset
               spriteUV.x += int(fmod(timeVal,_CellAmountCol));
               // calculate y offset
               spriteUV.y += int(timeVal/_CellAmountCol);

               // scale it to cell
               spriteUV.x *= cellUVPercentageX;
               spriteUV.y *= cellUVPercentageY;

               half4 c = tex2D (_MainTex, spriteUV);
               o.Albedo = c.rgb;
               o.Alpha = c.a;
          }
          ENDCG
     }
     FallBack "Diffuse"
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值