【Unity Shader系列】第二篇:ShaderLab语法——Unity Shader的脚手架

第二篇:ShaderLab语法——Unity Shader的脚手架

核心思想

在Unity中,一个.shader文件并不仅仅包含纯粹的HLSL代码。它是由一种名为ShaderLab的声明式语言组织起来的。ShaderLab是Unity为你提供的“脚手架”或“包装纸”,它用一种清晰的结构定义了Shader的属性、渲染设置和多个渲染子版本(SubShader),而你的HLSL代码(写在CGPROGRAMENDCG块中)是这个结构中最核心的“内容”。

你可以把它类比成一份产品说明书:

  • Properties:是说明书上的可调节旋钮和开关(比如颜色、滑块、纹理选择),暴露给材质Inspector面板。
  • SubShader/Pass:是说明书的安装指南,告诉GPU在不同的硬件或渲染环境下应该如何设置和执行这个Shader。
  • CGPROGRAM:是说明书最核心的技术原理和工作细节,只有GPU这位“工程师”会仔细阅读并执行它。

ShaderLab 基本结构解剖

一个最基本的ShaderLab文件结构如下,我们逐块解析:
(语言为glsl)

// 1. 定义Shader在菜单中的路径
Shader "MyShaders/SimpleShader" 
{
    // 2. 属性块:定义在材质面板上可见的可调参数
    Properties 
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Tint Color", Color) = (1,1,1,1)
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
    }

    // 3. 子着色器块:可以定义多个以适应不同硬件,至少一个
    SubShader 
    {
        // 4. 标签:告诉引擎如何以及何时渲染这个SubShader
        Tags { "RenderType"="Opaque" }

        // 5. 渲染通道(Pass):一次完整的渲染流程。一个SubShader可包含多个Pass
        Pass 
        {
            // 6. 开始CG代码片段
            CGPROGRAM

            // 7. 编译指令:声明顶点着色器和片元着色器的函数名
            #pragma vertex vert
            #pragma fragment frag

            // 8. 引入常用的内置函数和变量
            #include "UnityCG.cginc"

            // 9. 定义与Properties块关联的变量
            sampler2D _MainTex;
            float4 _MainTex_ST; // 注意:自动生成的纹理缩放偏移变量
            fixed4 _Color;

            // 10. 定义输入结构体(从CPU到顶点着色器)
            struct appdata
            {
                float4 vertex : POSITION; // 顶点位置(语义绑定)
                float2 uv : TEXCOORD0;    // 第一套UV坐标
            };

            // 11. 定义输出结构体(从顶点着色器到片元着色器)
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION; // 裁剪空间位置(必须)
            };

            // 12. 顶点着色器函数
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex); // 核心变换函数
                o.uv = TRANSFORM_TEX(v.uv, _MainTex); // 应用纹理缩放偏移
                return o;
            }

            // 13. 片元着色器函数
            fixed4 frag (v2f i) : SV_Target
            {
                // 采样纹理,并乘以颜色属性
                fixed4 col = tex2D(_MainTex, i.uv) * _Color;
                return col;
            }
            ENDCG // 结束CG代码片段
        }
    }
    // 14. 后备Shader(可选)
    FallBack "Diffuse"
}

关键部分详解

  1. Properties 属性块:

    • 这是你与美术师或自己交互的界面。
    • 语法:_VariableName ("Display Name", Type) = DefaultValue {}
    • 常见类型:2D(纹理),Color(颜色),Range(min, max)(滑块),Float(浮点数),Vector(四维向量)。
  2. SubShader 和 Pass:

    • 一个Shader可以有多个SubShader。Unity会从上到下检查第一个能被目标硬件支持的SubShader。这用于为不同性能的显卡提供不同效果的版本。
    • 每个SubShader可以包含多个Pass每个Pass意味着一次完整的渲染流程。多Pass用于实现复杂的、需要渲染多次的效果(如描边、法线 extrusion 等),但性能开销较大。
  3. Tags:

    • 以键值对的形式提供一些“提示”,告诉渲染引擎如何渲染这个SubShader或Pass。
    • 例如:"RenderType"="Opaque"(是不透明物体),"Queue"="Geometry"(渲染队列是几何体,即2000)。
  4. CGPROGRAM 中的关键:

    • #pragma vertex [functionName]:告诉Unity哪个函数是顶点着色器。
    • #pragma fragment [functionName]:告诉Unity哪个函数是片元着色器。
    • #include "UnityCG.cginc"极其重要!它包含了Unity预提供的大量帮助函数、宏和内置变量(如UnityObjectToClipPos),能极大简化你的代码。
    • 变量传递:在Properties中定义的变量,必须在CG代码段中重新声明一遍(如sampler2D _MainTex;)才能使用。注意:声明一个_MainTex纹理时,Unity会自动生成一个_MainTex_ST(ST = Scale & Tiling)变量来存储其缩放和偏移值。
  5. 结构体 (appdata, v2f):

    • appdata:输入到顶点着色器的数据模型。用语义(: POSITION) 来标明每个变量的用途。
    • v2f(vertex-to-fragment):顶点着色器输出、并插值后传递给片元着色器的数据。同样使用语义。
  6. 语义 (Semantics):

    • 这是HLSL中连接数据和管线特定角色的桥梁。
    • : POSITION:表示这是顶点位置。
    • : TEXCOORD0:表示这是一套纹理坐标。
    • : SV_POSITION:表示这个值是裁剪空间的位置(顶点着色器输出必须包含这个)。
    • : SV_Target:表示片元着色器输出的颜色值要渲染到目标渲染纹理(屏幕)。

下一步行动

  1. 在Unity中,创建一个Unlit Shader,将其命名为SimpleShader
  2. 用上面的代码完全替换掉默认内容。
  3. 创建一个材质,使用这个Shader,并赋予一个纹理。
  4. 尝试调节_Color属性,观察效果。恭喜你,你已经成功创建并运行了你的第一个自定义Shader!

下一篇预告:《第三篇:HLSL语法基础——Shader的编程语言》。我们将暂时离开ShaderLab框架,深入学习了HLSL语言的基本语法、数据类型和核心函数,为你编写更复杂的着色器逻辑打下坚实基础。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值