Shader编写指南(三):ShaderLab详解

ShaderLab 是 Unity 中用于定义着色器(Shader)结构的声明式语言,通过嵌套括号语法描述着色器对象的各个组成部分。它不直接实现渲染逻辑,而是作为容器整合 HLSL 代码、设置渲染状态,并暴露可编辑的材质参数。以下是 ShaderLab 的核心功能与使用指南:

一、ShaderLab 的核心职责

ShaderLab 主要用于定义着色器的框架结构元数据,具体包括:

  1. 着色器整体结构

    • 声明着色器名称、属性、子着色器(SubShader)和回退方案(Fallback)。
    • 示例:

      hlsl

      Shader "Custom/MyShader" {  
          // 属性定义  
          Properties {  
              _MainTex ("Texture", 2D) = "white" {}  
          }  
          // 子着色器列表  
          SubShader {  
              // 渲染状态与 Pass 定义  
              Pass { ... }  
          }  
          // 回退着色器  
          Fallback "Legacy Shaders/Diffuse"  
      }  
      
  2. 整合 HLSL 代码

    • 通过 CGPROGRAM/ENDCG 代码块嵌入顶点、片元等着色器程序。

    hlsl

    Pass {  
        CGPROGRAM  
        #pragma vertex vert  
        #pragma fragment frag  
        // HLSL 代码  
        ENDCG  
    }  
    
  3. 设置 GPU 渲染状态

    • 定义混合模式、深度测试、剔除模式等渲染状态指令(如 Blend SrcAlpha OneMinusSrcAlpha)。
  4. 暴露材质参数

    • 在 Properties 块中声明可在材质面板编辑的参数(如纹理、颜色、数值)。
二、ShaderLab 关键语法与结构
1. 着色器声明(Shader Declaration)

hlsl

Shader "Shader路径/名称" {  
    // 内容块  
}  

  • 路径命名规则:决定材质面板中的分类层级(如 "Custom/Effects/Glow" 会显示在 Custom > Effects 下)。
  • 示例Shader "URP/MyLitShader"
2. 属性块(Properties Block)

定义材质面板可见的参数,格式为 属性名 ("显示名称", 类型) = 默认值

类型说明示例
Color颜色(RGBA)_TintColor ("Tint", Color) = (1,1,1,1)
2D二维纹理(带 Alpha 通道)_MainTex ("Texture", 2D) = "white" {}
Range(min, max)浮点范围滑块_GlowIntensity ("Glow Intensity", Range(0, 5)) = 1
Vector四维向量(XYZW)_UVScale ("UV Scale", Vector) = (1,1,0,0)

  • 用途:参数值会被传递给 HLSL 代码,通过同名变量引用。
3. 子着色器块(SubShader Block)

每个着色器可包含多个 SubShader,Unity 会按顺序尝试渲染,直到找到硬件支持的版本。

hlsl

SubShader {  
    Tags { "渲染标签"="值" } // 定义渲染队列、光照模式等  
    LOD 200 // 细节层级(Level of Detail)  
    Pass { ... } // 至少包含一个 Pass  
    // 可选:其他 Pass 或 UsePass 引用  
}  

  • 核心标签(Tags)
    • RenderType:定义渲染队列(如 "Opaque"=2000,"Transparent"=3000)。
    • LightMode:指定 Pass 的光照模式(如 "ForwardBase" 用于正向渲染主光源)。
  • LOD 作用:当材质 LOD 等级低于当前 SubShader 的 LOD 值时,会跳过该 SubShader。
4. 通道块(Pass Block)

每个 Pass 定义一次完整的渲染流程,包含渲染状态指令和 HLSL 代码。

hlsl

Pass {  
    // 渲染状态指令(如混合、深度测试)  
    Blend SrcAlpha OneMinusSrcAlpha  
    ZTest LEqual  
    // 嵌入 HLSL 代码  
    CGPROGRAM  
    #pragma vertex vert  
    #pragma fragment frag  
    // 顶点和片元着色器函数  
    ENDCG  
}  
  • 常用渲染状态指令
    • Cull Off:关闭背面剔除(显示双面)。
    • Offset 2, 2:设置深度偏移,避免 Z 冲突。
    • ColorMask RGB:仅渲染 RGB 通道,忽略 Alpha。
5. 回退机制(Fallback)

当所有 SubShader 均不被支持时,使用指定的回退着色器。

hlsl

Fallback "Legacy Shaders/VertexLit"  

  • 最佳实践:回退至简单着色器(如 VertexLit),确保低端设备可渲染。
6. 包依赖(Package Requirements)

通过 ShaderLab: requires 声明 SubShader 或 Pass 依赖的资源包。

hlsl

SubShader {  
    Requires "PackageName" // 如 "PostProcessing"  
    Pass {  
        Requires "ShaderFeatureName" // 如 "DIRECTIONAL_LIGHT"  
    }  
}  

  • 用途:仅当项目安装指定包时,才编译对应的 SubShader/Pass。
三、HLSL 代码嵌入与交互

ShaderLab 通过 CGPROGRAM 块整合 HLSL 代码,并支持以下指令:

  1. 编译指令

    • #pragma vertex 函数名:指定顶点着色器函数。
    • #pragma fragment 函数名:指定片元着色器函数。
    • #include "UnityCG.cginc":导入 Unity 内置函数库(如坐标转换、光照计算)。
  2. 引用 ShaderLab 属性
    在 HLSL 中声明与 Properties 同名的变量,类型需匹配:

    hlsl

    sampler2D _MainTex; // 对应 2D 纹理属性  
    float4 _MainTex_ST; // Unity 自动生成的 UV 变换参数(ST 代表 Scale/Translate)  
    fixed4 _TintColor; // 对应 Color 属性  
    
四、典型应用场景
1. 基础漫反射材质

hlsl

Shader "Custom/Diffuse" {  
    Properties {  
        _MainTex ("Texture", 2D) = "white" {}  
        _Color ("Tint", Color) = (1,1,1,1)  
    }  
    SubShader {  
        Tags { "RenderType"="Opaque" }  
        LOD 100  
        Pass {  
            CGPROGRAM  
            #pragma vertex vert  
            #pragma fragment frag  
            #include "UnityCG.cginc"  
            sampler2D _MainTex;  
            float4 _MainTex_ST;  
            fixed4 _Color;  
            struct appdata {  
                float4 vertex : POSITION;  
                float2 uv : TEXCOORD0;  
            };  
            struct v2f {  
                float2 uv : TEXCOORD0;  
                float4 pos : SV_POSITION;  
            };  
            v2f vert (appdata v) {  
                v2f o;  
                o.pos = UnityObjectToClipPos(v.vertex);  
                o.uv = TRANSFORM_TEX(v.uv, _MainTex); // 应用 UV 变换  
                return o;  
            }  
            fixed4 frag (v2f i) : SV_TARGET {  
                fixed4 tex = tex2D(_MainTex, i.uv);  
                return tex * _Color; // 颜色混合  
            }  
            ENDCG  
        }  
    }  
    Fallback "Diffuse"  
}  
2. 透明混合材质

hlsl

Shader "Custom/Transparent" {  
    Properties {  
        _MainTex ("Texture", 2D) = "white" {}  
    }  
    SubShader {  
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }  
        Blend SrcAlpha OneMinusSrcAlpha // 开启透明混合  
        LOD 100  
        Pass {  
            CGPROGRAM  
            #pragma vertex vert  
            #pragma fragment frag  
            #include "UnityCG.cginc"  
            sampler2D _MainTex;  
            struct appdata {  
                float4 vertex : POSITION;  
                float2 uv : TEXCOORD0;  
            };  
            struct v2f {  
                float2 uv : TEXCOORD0;  
                float4 pos : SV_POSITION;  
            };  
            v2f vert (appdata v) {  
                v2f o;  
                o.pos = UnityObjectToClipPos(v.vertex);  
                o.uv = v.uv;  
                return o;  
            }  
            fixed4 frag (v2f i) : SV_TARGET {  
                return tex2D(_MainTex, i.uv);  
            }  
            ENDCG  
        }  
    }  
    Fallback "Transparent/Diffuse"  
}  
五、最佳实践与注意事项
  1. 性能优化

    • 减少 SubShader 数量:避免为每个平台单独编写 SubShader,优先通过 #pragma multi_compile 生成变体。
    • 合并 Pass:使用 MultiCompile 或 ShaderVariantCollection 减少重复 Pass。
  2. 跨平台兼容

    • 使用 Unity 内置宏(如 UNITY_SAMPLE_TEX2D)进行纹理采样,避免直接调用平台特定函数。
    • 通过 Tags { "RenderType"="Opaque" } 统一渲染队列,避免排序问题。
  3. 调试技巧

    • 在 frag 函数中返回中间变量(如法线、UV),辅助定位问题:

      hlsl

      fixed4 frag(v2f i) : SV_TARGET {  
          return fixed4(i.uv, 0, 1); // 可视化 UV 分布  
      }  
      

    • 使用 ShaderLab: debug 指令输出渲染状态信息(如 Debug("Draw Calls", 100))。
六、与 Shader Graph 的关系

Shader Graph 本质上是 ShaderLab 的可视化封装,其生成的代码结构与手动编写的 ShaderLab/HLSL 代码一致。例如:

  • Shader Graph 中的节点参数会映射为 ShaderLab 的 Properties
  • 节点逻辑会转换为 HLSL 函数,并嵌入 Pass 的 CGPROGRAM 块中。

对于复杂效果,可通过 Shader Graph 快速搭建框架,再手动编辑生成的 HLSL 代码进行优化。

总结

ShaderLab 是 Unity 着色器开发的基础,其核心价值在于结构化定义渲染流程抽象硬件差异。通过组合 PropertiesSubShaderPass 和 HLSL 代码,开发者可灵活控制材质的外观与性能。尽管 Shader Graph 简化了多数场景的开发,但深入理解 ShaderLab 仍是掌握高级渲染技术(如自定义光照模型、多 Pass 渲染)的必经之路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李也疯狂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值