基本结构

图片
图片

SubShader Tags

Render Type

图片
图片

Queue

图片
图片

LOD

SubShader
{
    LOD 300  // ← 这就是LOD关键字
    Pass { }
}
// C#代码中设置 Shader.globalMaximumLOD = 200;
// 只使用LOD<=200的SubShader 

选择规则: 如果设置 Shader.globalMaximumLOD = 200 SubShader LOD 300 ← 跳过(超过限制) SubShader LOD 200 ← ✅ 使用这个 SubShader LOD 100 ← 不会用到(因为已经找到合适的)

Unity内置Shader的LOD标准

Unity官方推荐的LOD值

LOD值质量等级示例Shader
600+最高质量物理基础渲染 + 曲面细分
500非常高VertexLit + 所有像素光
300高Diffuse + Specular + Normal Map
200中Diffuse + Specular
150中低Diffuse + 简化光照
100低Vertex Lit(顶点光照)
50最低无光照
Unity内置Shader的LOD值:

Standard Shader = 300 Bumped Specular = 300 Bumped Diffuse = 200 Diffuse = 200 Specular = 200 VertexLit = 100 Unlit = 100

IgnoreProjector

忽略投影

Tags { "IgnoreProjector"="True" }
图片
图片

ForceNoShadowCasting

Tags { "ForceNoShadowCasting"="True" }
图片
图片

DisableBatching

Tags { "DisableBatching"="True" }
图片
图片

PreviewType

细节面板预览形状

Tags { "PreviewType"="Plane" }
图片
图片

CanUseSpriteAtlas

Tags { "CanUseSpriteAtlas"="True" }
图片
图片

Pass Tags

LightMode

图片
图片
图片
图片

RequireOptions

图片
图片

PassFlags

图片
图片

Pass keyworld

Cull

图片
图片
图片
图片

ZTest

图片
图片
// 普通物体(默认)
Pass
{
    ZTest LEqual  // 近的覆盖远的
}

// 透视效果(X光)
Pass
{
    ZTest Greater  // 只显示被遮挡的部分
    
    CGPROGRAM
    fixed4 frag() : SV_Target
    {
        return fixed4(1, 0, 0, 0.5);  // 半透明红色
    }
    ENDCG
}

// UI/屏幕空间效果
Pass
{
    ZTest Always  // 忽略深度,总是显示
}

// 描边效果(两个Pass)
// Pass 1: 正常渲染
Pass
{
    ZTest LEqual
    CGPROGRAM
    // 正常渲染
    ENDCG
}

// Pass 2: 描边
Pass
{
    ZTest Greater  // 只渲染被遮挡的部分作为描边
    CGPROGRAM
    // 放大模型,渲染边缘
    ENDCG
}

ZWrite

图片
图片
图片
图片

Blend 混合模式

// 基础语法
Blend SrcFactor DstFactor
Blend SrcFactor DstFactor, SrcFactorA DstFactorA  // 分别控制RGB和Alpha

// 高级语法
BlendOp Add/Sub/RevSub/Min/Max  // 混合操作

混合因子:

因子含义
One1
Zero0
SrcColor源颜色
SrcAlpha源Alpha
DstColor目标颜色
DstAlpha目标Alpha
OneMinusSrcColor1 - 源颜色
OneMinusSrcAlpha1 - 源Alpha
OneMinusDstColor1 - 目标颜色
OneMinusDstAlpha1 - 目标Alpha

混合公式:

最终颜色 = (源颜色 * SrcFactor) BlendOp (目标颜色 * DstFactor)

常用混合模式

// 1. 标准Alpha混合(透明)⭐⭐⭐⭐⭐
Blend SrcAlpha OneMinusSrcAlpha
// 最终 = 源颜色 * 源Alpha + 目标颜色 * (1 - 源Alpha)

// 2. 加法混合(发光、粒子)⭐⭐⭐⭐⭐
Blend One One
// 最终 = 源颜色 + 目标颜色

Blend SrcAlpha One  // 柔和的加法
// 最终 = 源颜色 * 源Alpha + 目标颜色

// 3. 乘法混合(阴影、滤镜)⭐⭐⭐
Blend DstColor Zero
// 最终 = 目标颜色 * 源颜色

Blend Zero SrcColor  // 等价写法
// 最终 = 源颜色 * 目标颜色

// 4. 正片叠底(Photoshop的Multiply)
Blend DstColor SrcColor
// 最终 = 源颜色 * 目标颜色 + 目标颜色 * 源颜色

// 5. 减法混合⭐⭐
BlendOp Sub
Blend One One
// 最终 = 源颜色 - 目标颜色

BlendOp RevSub
Blend One One
// 最终 = 目标颜色 - 源颜色

// 6. 最小值/最大值
BlendOp Min
Blend One One
// 最终 = min(源颜色, 目标颜色)

BlendOp Max
Blend One One
// 最终 = max(源颜色, 目标颜色)

// 7. 预乘Alpha
Blend One OneMinusSrcAlpha
// 用于已经预乘了Alpha的纹理

// 8. 柔光(Soft Additive)
Blend OneMinusDstColor One
// 亮处更亮,暗处影响小

// 9. 线性减淡(Screen)
Blend OneMinusDstColor One
Blend One OneMinusSrcColor

实际应用示例:

// 火焰粒子(加法混合)
Pass
{
    ZWrite Off
    Blend SrcAlpha One  // 柔和加法
    
    CGPROGRAM
    fixed4 frag() : SV_Target
    {
        fixed4 col = tex2D(_MainTex, i.uv);
        col.rgb *= _TintColor.rgb * 2;  // 增强亮度
        return col;
    }
    ENDCG
}

// 玻璃(标准透明)
Pass
{
    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha
    
    CGPROGRAM
    fixed4 frag() : SV_Target
    {
        fixed4 col = tex2D(_MainTex, i.uv);
        col.a = 0.3;  // 30%透明度
        return col;
    }
    ENDCG
}

// 阴影投射(乘法混合)
Pass
{
    ZWrite Off
    Blend DstColor Zero  // 正片叠底
    
    CGPROGRAM
    fixed4 frag() : SV_Target
    {
        return fixed4(0.5, 0.5, 0.5, 1);  // 50%变暗
    }
    ENDCG
}

ColorMask(颜色遮罩)

ColorMask RGB   // 写入RGB(默认)
ColorMask A     // 只写入Alpha
ColorMask 0     // 不写入任何颜色
ColorMask RGBA  // 写入所有通道

// 组合使用
ColorMask R     // 只写红色
ColorMask RG    // 写红色和绿色
ColorMask BA    // 写蓝色和Alpha

应用场景:

// 只写深度,不写颜色(透明物体预处理)
Pass
{
    ZWrite On
    ColorMask 0  // 不写任何颜色
}

// 只写Alpha通道
Pass
{
    ColorMask A
    CGPROGRAM
    fixed4 frag() : SV_Target
    {
        return fixed4(0, 0, 0, _Alpha);
    }
    ENDCG
}

// 模板缓冲配合使用
Pass
{
    ColorMask 0  // 不写颜色
    
    Stencil
    {
        Ref 1
        Comp Always
        Pass Replace
    }
}

Offset(深度偏移)

Offset Factor, Units

作用:

  • 调整深度值,避免Z-Fighting(深度冲突)
  • Factor:基于多边形斜率的偏移
  • Units:固定单位偏移

应用场景:

// 贴花(Decal)
Pass
{
    Offset -1, -1  // 向相机方向偏移,避免Z-Fighting
    
    CGPROGRAM
    // 渲染贴花
    ENDCG
}

// 描边效果
Pass
{
    Cull Front
    Offset 1, 1  // 向后偏移
    
    CGPROGRAM
    // 渲染背面作为描边
    ENDCG
}

Stencil(模板缓冲)

Stencil
{
    Ref [_RefValue]         // 参考值(0-255)
    ReadMask [_ReadMask]    // 读取遮罩(默认255)
    WriteMask [_WriteMask]  // 写入遮罩(默认255)
    
    Comp [comparison]       // 比较函数
    Pass [stencilOp]        // 测试通过时的操作
    Fail [stencilOp]        // 测试失败时的操作
    ZFail [stencilOp]       // 深度测试失败时的操作
}

比较函数(Comp):

  • Never - 永不通过
  • Less - 小于
  • Equal - 等于
  • LEqual - 小于等于
  • Greater - 大于
  • NotEqual - 不等于
  • GEqual - 大于等于
  • Always - 总是通过

操作(Pass/Fail/ZFail):

  • Keep - 保持不变
  • Zero - 设为0
  • Replace - 替换为Ref值
  • IncrSat - 加1(饱和,最大255)
  • DecrSat - 减1(饱和,最小0)
  • Invert - 按位取反
  • IncrWrap - 加1(循环)
  • DecrWrap - 减1(循环)

实际应用:遮罩效果

// 示例1:遮罩与被遮罩物体

// 遮罩物体(写入模板值)
Shader "Custom/StencilMask"
{
    SubShader
    {
        Tags { "Queue"="Geometry-1" }  // 先渲染
        
        Pass
        {
            ZWrite Off
            ColorMask 0  // 不写颜色
            
            Stencil
            {
                Ref 1
                Comp Always
                Pass Replace  // 写入模板值1
            }
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            float4 frag() : SV_Target
            {
                return 0;
            }
            ENDCG
        }
    }
}

// 被遮罩物体(只在遮罩内显示)
Shader "Custom/StencilObject"
{
    SubShader
    {
        Tags { "Queue"="Geometry" }
        
        Pass
        {
            Stencil
            {
                Ref 1
                Comp Equal  // 只在模板值等于1的地方渲染
            }
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            fixed4 frag() : SV_Target
            {
                return fixed4(1, 0, 0, 1);
            }
            ENDCG
        }
    }
}

示例2:描边效果

SubShader
{
    // Pass 1: 写入模板
    Pass
    {
        Stencil
        {
            Ref 1
            Comp Always
            Pass Replace
        }
        
        CGPROGRAM
        // 正常渲染物体
        ENDCG
    }
    
    // Pass 2: 描边(只在物体外部)
    Pass
    {
        Cull Front
        
        Stencil
        {
            Ref 1
            Comp NotEqual  // 不等于1的地方(物体外部)
        }
        
        CGPROGRAM
        // 放大并渲染描边
        v.vertex.xyz += v.normal * _OutlineWidth;
        ENDCG
    }
}

示例3:传送门效果

// 传送门遮罩
Shader "Custom/PortalMask"
{
    SubShader
    {
        Pass
        {
            ZWrite Off
            ColorMask 0
            
            Stencil
            {
                Ref 1
                Comp Always
                Pass Replace
            }
        }
    }
}

// 传送门另一侧的场景
Shader "Custom/PortalView"
{
    SubShader
    {
        Pass
        {
            Stencil
            {
                Ref 1
                Comp Equal
            }
            
            CGPROGRAM
            // 渲染另一个场景
            ENDCG
        }
    }
}

AlphaToMask(Alpha转遮罩)

AlphaToMask On   // 开启(MSAA时有效)
AlphaToMask Off  // 关闭(默认)

作用:

  • 将Alpha值转换为覆盖遮罩
  • 用于抗锯齿(需要开启MSAA)
  • 适合植被等Alpha Test物体

应用场景:

// 树叶Shader(更好的边缘)
Pass
{
    AlphaToMask On
    
    CGPROGRAM
    fixed4 frag() : SV_Target
    {
        fixed4 col = tex2D(_MainTex, i.uv);
        clip(col.a - _Cutoff);
        return col;
    }
    ENDCG
}

Conservative(保守光栅化)

Conservative True   // 开启保守光栅化
Conservative False  // 关闭(默认)

作用:

  • 高级功能,确保三角形完全覆盖的像素都被渲染
  • 需要硬件支持

常见组合总结

效果类型CullZTestZWriteBlend
不透明物体BackLEqualOnOff
标准透明BackLEqualOffSrcAlpha OneMinusSrcAlpha
加法粒子OffLEqualOffOne One
描边FrontLEqualOnOff
UIOffAlwaysOffSrcAlpha OneMinusSrcAlpha
天空盒FrontLEqualOffOff
X光透视BackGreaterOffSrcAlpha OneMinusSrcAlpha

target

Shader Model版本,可以省略。Unity会使用默认值:target 2.5

语法

#pragma target 2.0  // 指定最低Shader Model版本
#pragma target 2.5
#pragma target 3.0
#pragma target 3.5
#pragma target 4.0
#pragma target 4.5
#pragma target 5.0
#pragma target 6.0

Unity的Shader Model版本对照

Unity TargetShader Model对应年代平台支持关键功能
2.0SM 2.02004所有平台基础着色器
2.5SM 2.0扩展2005PC, Console更多指令
3.0SM 3.02006PC, Console, 高端移动MRT, 更多插值器
3.5 (GL ES 3.0)SM 3.0+2012现代移动MRT, Compute Shader
4.0SM 4.02008DX10+几何着色器
4.5SM 4.52009DX11+曲面细分
5.0SM 5.02011DX11+完整Compute Shader
6.0SM 6.02018DX12, Vulkan光线追踪、Mesh Shader

顶点/片元着色器

结构体

struct appdata
{
    float4 vertex : POSITION;   // 顶点位置
    float3 normal : NORMAL;     // 法线
    float4 tangent : TANGENT;   // 切线
    float2 uv : TEXCOORD0;      // UV0
    float2 uv1 : TEXCOORD1;     // UV1(光照贴图)
    float4 color : COLOR;       // 顶点颜色
};

完整的顶点输入语义列表:

语义含义数据类型
POSITION顶点位置(模型空间)float4
NORMAL法线(模型空间)float3
TANGENT切线(模型空间)float4
TEXCOORD0第一套UVfloat2/float4
TEXCOORD1第二套UV(光照贴图)float2/float4
TEXCOORD2第三套UVfloat2/float4
TEXCOORD3第四套UVfloat2/float4
COLOR顶点颜色float4
SV_VertexID顶点IDuint
SV_InstanceID实例ID(GPU Instancing)uint

TEXCOORD的数量限制

不同Shader Model的支持

Shader Model 2.0:

  • 最多8个TEXCOORD(0-7)
  • 每个最多float4
  • 总共32个float Shader Model
  • 3.0:
  • 最多10个TEXCOORD(0-9)
  • 每个最多float4
  • 总共40个float Shader Model
  • 4.0+:
  • 最多16个插值器 - 使用不同的命名(但TEXCOORD仍然有效) Unity默认:

pragma target 2.5

  • 支持10个TEXCOORD(0-9) 如果需要更多:

pragma target 3.0 或更高

完整支持表

Shader ModelTEXCOORD数量每个类型总float数Unity target
SM 2.08 (0-7)float432target 2.0
SM 2.510 (0-9)float440target 2.5(默认)
SM 3.010 (0-9)float440target 3.0
SM 4.0+16float464target 4.0+

片元输出语义

fixed4 frag(v2f i) : SV_Target  // ← 输出到渲染目标
{
    return fixed4(1, 0, 0, 1);  // 输出红色
}

常用输出语义: 这里语义主要是声明在Struct中的,片元后面默认就SV_Target或者说是SV_Target0,如果多输出的话就可以不写

语义含义用途
SV_Target渲染目标0输出颜色到屏幕
SV_Target0渲染目标0同上(明确写0)
SV_Target1渲染目标1多渲染目标(MRT)
SV_Target2渲染目标2MRT
SV_Target3渲染目标3MRT
SV_Depth深度值自定义深度
COLOR颜色(旧版)被SV_Target取代

延迟管线

多输出是使用延迟管线,先输出各个图,然后一起计算光照

// 必须用结构体 + MRT(但还是一个Pass!)
struct GBufferOutput
{
    fixed4 albedo : SV_Target0;
    fixed4 specular : SV_Target1;
    fixed4 normal : SV_Target2;
    fixed4 emission : SV_Target3;
};

GBufferOutput frag(v2f i)
{
    GBufferOutput o;
    o.albedo = tex2D(_MainTex, i.uv);
    o.specular = tex2D(_SpecMap, i.uv);
    o.normal = UnpackNormal(tex2D(_BumpMap, i.uv));
    o.emission = _Emission;
    return o;  // 同时输出4个值,只调用一次!
}

实现方法参考

SubShader
{
    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma target 3.0  // MRT需要SM3.0+
        
        sampler2D _MainTex;
        
        struct v2f
        {
            float4 pos : SV_POSITION;
            float2 uv : TEXCOORD0;
            float3 normal : TEXCOORD1;
            float depth : TEXCOORD2;
        };
        
        v2f vert(appdata_base v)
        {
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex);
            o.uv = v.texcoord;
            o.normal = UnityObjectToWorldNormal(v.normal);
            o.depth = o.pos.z;
            return o;
        }
        
        // 定义多输出结构体
        struct FragOutput
        {
            fixed4 albedo : SV_Target0;  // 输出到RT0
            fixed4 normal : SV_Target1;  // 输出到RT1
            fixed4 depth : SV_Target2;   // 输出到RT2
        };
        
        // 一次frag调用,同时输出3个值
        FragOutput frag(v2f i)
        {
            FragOutput o;
            
            // 同时计算所有数据
            o.albedo = tex2D(_MainTex, i.uv);
            o.normal = fixed4(normalize(i.normal) * 0.5 + 0.5, 1);
            o.depth = fixed4(i.depth, i.depth, i.depth, 1);
            
            // 一次return,同时输出到3个RT
            return o;
        }
        ENDCG
    }
}

// 优点:
// - 只执行一次顶点着色器
// - 只执行一次frag函数
// - GPU硬件支持,非常高效
// - 这就是延迟渲染的基础

C#端如何接收多渲染目标

using UnityEngine;

public class MRTExample : MonoBehaviour
{
    public Shader mrtShader;
    private Material mrtMaterial;
    
    private RenderTexture rt0;  // Albedo
    private RenderTexture rt1;  // Normal
    private RenderTexture rt2;  // Depth
    
    void Start()
    {
        // 创建3个RenderTexture
        rt0 = new RenderTexture(512, 512, 0);
        rt1 = new RenderTexture(512, 512, 0);
        rt2 = new RenderTexture(512, 512, 0);
        
        mrtMaterial = new Material(mrtShader);
    }
    
    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        // 设置多渲染目标(MRT)
        RenderBuffer[] colorBuffers = new RenderBuffer[3];
        colorBuffers[0] = rt0.colorBuffer;  // SV_Target0
        colorBuffers[1] = rt1.colorBuffer;  // SV_Target1
        colorBuffers[2] = rt2.colorBuffer;  // SV_Target2
        
        // 一次Graphics.Blit,同时输出到3个RT
        Graphics.SetRenderTarget(colorBuffers, rt0.depthBuffer);
        Graphics.Blit(source, mrtMaterial);
        
        // 现在rt0、rt1、rt2都已经填充了数据
        // 只调用了一次frag函数!
        
        // 显示结果
        Graphics.Blit(rt0, destination);  // 显示Albedo
    }
    
    // 调试:显示3个RT
    void OnGUI()
    {
        GUI.DrawTexture(new Rect(0, 0, 256, 256), rt0);
        GUI.DrawTexture(new Rect(256, 0, 256, 256), rt1);
        GUI.DrawTexture(new Rect(512, 0, 256, 256), rt2);
    }
}

数据类型快速参考表

一、精度类型对比

精度类型位数范围精度桌面性能移动性能跨平台一致性推荐度
half16位±60000~0.001等于float⭐⭐⭐⭐⭐⭐⭐✅ 主力
float32位±3.4×10³⁸~7位有效数字float⭐⭐⭐⭐⭐⭐✅ 必要时
fixed11位[-2, 2]~0.004等于float⭐⭐⭐⭐⭐❌ 避免

二、常用数据类型精度选择

数据类型推荐精度原因示例
🎨 颜色(RGB/RGBA)half4精度足够,跨平台一致half4 color
📐 法线half3归一化向量,精度足够half3 normal
📐 切线/副切线half3同法线half3 tangent
🗺️ UV坐标half2通常小范围half2 uv
💡 光照方向half3归一化向量half3 lightDir
👁️ 视线方向half3归一化向量half3 viewDir
✖️ 点积结果(NdotL等)half[-1,1]范围half ndotl
🎚️ PBR系数(金属度/粗糙度)half[0,1]范围half metallic
🎭 遮罩/Alphahalf[0,1]范围half mask
📦 纹理采样结果half4直接返回halfhalf4 tex2D(...)
🌍 世界空间坐标float3可能很大(几千米)float3 worldPos
📍 裁剪空间位置float4必须(SV_POSITION)float4 pos
🔢 矩阵float4x4精度要求高float4x4 matrix
⏱️ 时间/累加计算float避免精度损失float time
📏 大范围距离float可能很大float distance
📐 复杂数学函数floatsin/cos/exp等float sine