Unity3d Shader UV移动

本文使用UV偏移,创建车道方向动画

原始素材
原始素材

Unity3d Shader UV移动_第1张图片
最终效果(带水平向移动)

Unity3d纹理坐标

Unity3d Shader UV移动_第2张图片
偏移: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从上到下
Unity3d Shader UV移动_第3张图片Unity3d Shader UV移动_第4张图片


这里写图片描述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)


GPU实现

了解纹理坐标后。接下来,我们将编写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提取纹理。

CPU实现

为GPU计算的负担,可以将UV偏移的计算工作放到CPU中,最后将计算结果传回GPU渲染即可。下面是使用MonoBehaviour实现UV偏移代码。
主要使用到了Material.GetTextureOffsetSetTextureOffset对应纹理坐标Offset
Material.GetTextureScaleSetTextureScale对应纹理坐标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);
    }
}

你可能感兴趣的:(Unity3d,Shader,unity3d)