本文使用UV偏移,创建车道方向动画
偏移:Offset(xo,yo),将原点偏移到(xo,yo)。
平铺:Tiling(xt,yt),以偏移后的坐标为新原点,平铺(xt,yt)范围
Unity3d在创建Material,默认Offset = (0, 0),Tiling(1, 1)。即原点不偏移,平铺方向各1次。也就是原图显示。
Unity3d与OpenGl的纹理坐标同持一致。U方向从左到右,V方向从下到上。而DX U从左到右,V从上到下
Offset = (0, 0.5) Tiling = (0.5, 0.5)
Offset = (0.5, 0.5) Tiling = (0.5, 0.5)
Offset = (0, 0)Tiling = (0.5, 0.5)
Offset = (0.5, 0) Tiling = (0.5, 0.5)
Offset = (0, 0.5)Tiling = (1.0, 0.5)
Offset = (0, 0)Tiling = (1.0, 0.5)
Offset = (0, 0)Tiling = (0.5, 1)
Offset = (0.5, 0)Tiling = (0.5, 1)
了解纹理坐标后。接下来,我们将编写Shader实现车道方向动画。实现原理就是持续地修改贴图在U方向的偏移。(注意创建场景、GameObject、Material等基本操作不在此本文说明)。下面给出UV偏移的Shader代码。
Shader "Custom/UVOffset" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_USpeed("USpeed ", float) = 1.0
_UCount("UCount", float) = 1.0
_VSpeed("VSpeed", float) = 1.0
_VCount("VCount", float) = 1.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
// 贴图
sampler2D _MainTex;
// U轴方向滚动速度
float _USpeed;
// U轴方向平铺个数
float _UCount;
// V轴方向滚动速度
float _VSpeed;
// V轴方向平铺个数
float _VCount;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
float2 uv = IN.uv_MainTex;
float detalTime = _Time.x;
// 计算X轴方向变化
uv.x += detalTime * _USpeed;
uv.x *= _UCount;
// 计算Y轴方向变化
uv.y += detalTime * _VSpeed;
uv.y *= _VCount;
half4 c = tex2D (_MainTex, uv);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
顶点纹理 = 时间 * 速度
即 uv.x += _Time.x * _USpeed 其中_Time是Unity3d内置变量。
Name | Type | Value |
---|---|---|
_Time | float4 | Time (t/20, t, t*2, t*3), use to animate things inside the shaders. |
参考链接http://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
当前纹理(平铺)= 当前纹理 * 平铺个数
即 uv.x *= _UCount;
我们假设顶点范围[0,1],以U轴方向为例(顶点与纹理不是同一个东西)
在_UCount = 1的情况下,uv.x = uv.x * 1,顶点与纹理一一对应。
在_UCount = 2的情况下,uv.x = uv.x * 2, 原本水平方向x = 0.5顶点,这次由于uv.x * 2,抽取了uv.x = 1.0的纹理(也可以说是uv.x = 0.0的纹理)。即相比于_UCount = 1,这次在顶点从开始x = 0.5,便重新以uv.x =0提取纹理。
为GPU计算的负担,可以将UV偏移的计算工作放到CPU中,最后将计算结果传回GPU渲染即可。下面是使用MonoBehaviour实现UV偏移代码。
主要使用到了Material.GetTextureOffset、SetTextureOffset对应纹理坐标Offset
Material.GetTextureScale、SetTextureScale对应纹理坐标Tiling
using UnityEngine;
public class UVOffset: MonoBehaviour {
// U轴方向滚动速度
public float USpeed = 1.0f;
// U轴方向平铺个数
public int UCount = 1;
// V轴方向滚动速度
public float VSpeed = 1.0f;
// V轴方向平铺个数
public int VCount = 1;
private Material mat = null;
private void Awake()
{
if (this.renderer != null)
this.mat = this.renderer.material;
}
private void Update()
{
if (this.mat == null)
return;
Vector2 offset = this.mat.GetTextureOffset("_MainTex");
Vector2 tiling = this.mat.GetTextureScale("_MainTex");
offset.x += Time.deltaTime * USpeed;
offset.y += Time.deltaTime * VSpeed;
tiling.x = UCount;
tiling.y = VCount;
this.mat.SetTextureOffset("_MainTex", offset);
this.mat.SetTextureScale("_MainTex", tiling);
}
}