打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【新提醒】【【Unity Shaders】学习笔记
阅读本系列文章之前你需要有一些编程的概念。

在VS里面,Unity Shaders是没有语法高亮显示和智能提示的,VS党可以参考一下如何使代码高亮显示,也可以下载shaderlabvs或NShader之类的插件使代码高亮显示。

这是针对小白的Unity Shaders的基础知识,如果你已经有了基础或者你是大神,那么这些文章不适合你。

由于作者水平的局限,文中或许会有谬误之处,恳请指出。

通过更改Input结构体里UV坐标,我们可以让纹理动起来。

这是一段河流的简易Shader:

[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Shader "Custom/ScrollUVs" {
    Properties {       
        _MainTex ("Albedo (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
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows
        sampler2D _MainTex;
        fixed _ScrollXSpeed;
        fixed _ScrollYSpeed;
        struct Input {
            float2 uv_MainTex;
        };
        void surf (Input IN, inout SurfaceOutputStandard o) {
            fixed2 scrolledUV = IN.uv_MainTex;
            fixed xScrollValue = _ScrollXSpeed * _Time.y;
            fixed yScrollValue = _ScrollYSpeed * _Time.y;
            scrolledUV += fixed2(xScrollValue,yScrollValue);
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, scrolledUV);
            o.Albedo = c.rgb;      
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}


效果如下:



使用的是这张纹理:



原理很简单,看过前面的文章,你一定可以看懂这段代码,原理就是随着时间增加UV坐标x和y值。
这里有一个_Time变量我们没有见过,它是Unity内置的变量。

这是Unity对它的定义:

float4  _Time : Time (t/20, t, t*2, t*3), use to animate things inside the shaders

Unity官网Shaderlab内置变量介绍

_Time和C#里的Time.time变量类似,不同的是,它是一个四维向量,而不是标量。它包含四个不同大小的时间值,_Time.x就是二十分之一的时间。_Time.y、_Time.z、_Time.w同理。根据自己的需要选择某个分量。

现在介绍一下Sprite Animation。

有Unity经验的人,或许有用C#脚本写过精灵动画,那么用Shader写精灵动画原理也是一样的,也是使纹理坐标的Offset随着时间阶梯式变化。

代码如下:

[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Shader "Custom/AnimateSprites" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _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;
        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"
}


关键的地方也有注释,所以是很容易读懂的。
fmod是取余,ceil是向上取整。
需要说明一下的地方应该就是:
UV坐标乘某个数,相当于修改纹理的Tilling,UV坐标加上某个数,相当于修改纹理的Offset。

优化

上面的那个脚本只实现了x方向上的偏移,当然你也可以实现更多维度的精灵动画,只要添加y方向上的偏移即可。
但是这样做可能会使Shader进行大量的计算,影响程序性能。所以我们可以将计算坐标偏移的代码转移到C#中,让CPU分担一部分计算。
这是C#中的代码:

[C#] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
using UnityEngine;
using System.Collections;
public class SpriteAnimator : MonoBehaviour
{
     
    public float speed = 0.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 % cellAmount);
        transform.renderer.material.SetFloat("_TimeValue", timeValue);
    }
}


这就是在C#里将变量传递给shader的方法。这样就将一部分计算转移到了C#脚本中。
因为CPU更擅长复杂的、有逻辑的运算,而GPU擅长并行运算,所以对于顶点、像素之类的计算(通常是几百几千个相同但不复杂的计算),应该让GPU进行,而比较复杂的计算可以转移到CPU中,再把数据喂给GPU。这是优化性能的一个方法。


本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
猫都能学会的Unity3D Shader入门指南(一)
【Unity Shaders】Shader学习资源和Surface Shader概述
Unity3D Shader入门指南(二)
Unity3D Shader 使指定颜色过滤成透明
Unity3d游戏角色描边
【Unity Shader】Unity3D中的屏幕着色器和图像特效
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服