记录学习Unity Shader过程中学到的东西.


1️⃣Queue

在Unity Shader中,渲染队列(Queue)控制对象的渲染顺序。以下是常见的渲染队列类型及其用途:

内置渲染队列类型

  1. Background (1000)
    最早渲染的队列,常用于天空盒等背景元素。

  2. Geometry (2000)
    默认队列,用于大多数不透明物体(如地形、建筑、角色模型)。Unity会对该队列的物体进行深度排序和优化。

  3. AlphaTest (2450)
    用于使用Alpha测试的半透明物体(如栅栏、植被)。这类物体有明确的透明和不透明区域。

  4. Transparent (3000)
    用于需要透明度混合的物体(如玻璃、粒子效果)。此队列按从后到前的顺序渲染,以确保正确的混合效果。

  5. Overlay (4000)
    最后渲染的队列,常用于UI元素或全屏效果,确保它们显示在最上层。

自定义队列

你可以通过指定具体数值来创建自定义队列,例如:

SubShader {
    Tags { "Queue" = "Geometry+100" } // 在Geometry队列后100的位置渲染
    // 其他Shader代码
}

注意事项

  • 性能优化:合理使用队列可以避免不必要的Overdraw。
  • 透明物体:使用Transparent队列时,需确保物体的几何结构简单且已按距离排序。
  • 渲染顺序冲突:相邻队列的物体会按提交顺序渲染,可能导致意外的遮挡问题,需谨慎调整。

这些队列类型覆盖了Unity中大多数渲染需求,合理配置可确保场景正确显示。


2️⃣RenderType

在Unity Shader中,RenderType是一个重要的标签,用于将Shader分类到特定的渲染类型中。这有助于Unity在特定场景(如延迟渲染、光照贴图、着色器替换)中正确处理材质。以下是RenderType的主要作用和常见类型:

RenderType的作用

  1. 着色器替换(Shader Replacement)
    通过指定RenderType,可在运行时替换特定类型的Shader(例如只渲染所有不透明物体或所有透明物体)。

  2. 光照模式适配
    帮助Unity识别Shader是否支持特定光照模式(如前向渲染、延迟渲染)。

  3. 特殊效果处理
    例如在使用雾效、全局光照(GI)或后处理时,Unity会根据RenderType做出不同处理。

常见RenderType标签值

以下是Unity内置的主要RenderType及其用途:

1. Opaque

  • 用途:用于不透明物体(如地形、金属、石头)。
  • 特点:默认使用前向渲染,支持光照贴图和延迟渲染。
  • 示例
    Tags { "RenderType" = "Opaque" }
    

2. Transparent

  • 用途:用于需要透明度混合的物体(如玻璃、粒子效果)。
  • 特点:不支持延迟渲染,依赖于渲染队列(通常为Queue=Transparent)。
  • 示例
    Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
    

3. TransparentCutout

  • 用途:用于使用Alpha测试的半透明物体(如栅栏、植被)。
  • 特点:支持光照贴图和延迟渲染,但需使用ZWrite On
  • 示例
    Tags { "RenderType" = "TransparentCutout" "Queue" = "AlphaTest" }
    

4. Background

  • 用途:用于背景元素(如天空盒)。
  • 特点:通常在渲染队列的早期(Queue=Background)渲染。
  • 示例
    Tags { "RenderType" = "Background" "Queue" = "Background" }
    

5. Overlay

  • 用途:用于UI或覆盖效果(如屏幕特效)。
  • 特点:通常在渲染队列的最后(Queue=Overlay)渲染。
  • 示例
    Tags { "RenderType" = "Overlay" "Queue" = "Overlay" }
    

6. TreeOpaque / TreeTransparentCutout / TreeBillboard

  • 用途:专用于地形树木系统的RenderType。
  • 特点:与Unity的树烘焙和动画系统协同工作。

7. Grass / GrassBillboard

  • 用途:专用于地形草皮系统的RenderType。
  • 特点:优化了草的渲染和碰撞。

自定义RenderType

你可以定义自己的RenderType,但通常需要与内置类型配合使用。例如:

Tags { "RenderType" = "CustomType" }

自定义类型在着色器替换时非常有用,但需确保在替换Shader中正确处理。

RenderType vs Queue

  • RenderType:分类Shader的功能类型(如不透明、透明)。
  • Queue:控制具体的渲染顺序(如GeometryTransparent队列)。

两者通常结合使用,例如:

SubShader {
    Tags { 
        "RenderType" = "TransparentCutout" 
        "Queue" = "AlphaTest" 
    }
    // 其他Shader代码
}

最佳实践

  1. 遵循Unity规范:优先使用内置RenderType,确保与引擎功能兼容。
  2. 避免重复定义:除非必要,不要创建新的RenderType。
  3. 性能考虑:透明物体(RenderType=Transparent)会禁用延迟渲染,可能影响性能。

通过合理设置RenderType和Queue,可确保Shader在各种场景下正确渲染,并充分利用Unity的优化机制。


3️⃣DisableBatching

在Unity Shader中,DisableBatching是一个重要的标签,用于控制GPU实例化(GPU Instancing)和批处理(Batching)的行为。以下是其作用、常见用法和注意事项:

DisableBatching的作用

批处理是Unity优化渲染性能的重要手段,通过合并多个网格(Mesh)减少Draw Call。但某些情况下,批处理会破坏Shader的功能,此时需要禁用它。

DisableBatching标签有三种取值

  1. True:完全禁用批处理(包括静态批处理和动态批处理)。
  2. False:不禁用批处理(默认值)。
  3. LODFading:仅在使用LOD淡入淡出时禁用批处理(针对Unity的LOD系统)。

何时需要禁用批处理?

1. 使用模型空间坐标

若Shader依赖模型空间坐标(如_World2Object矩阵),批处理会导致多个物体共用同一组坐标,造成渲染错误。
示例场景

  • 顶点动画(如布料、草随风摆动)。
  • 基于模型中心的特效(如武器发光)。
Tags { "DisableBatching" = "True" }
// 依赖模型空间坐标的顶点着色器
v2f vert(appdata v) {
    v.vertex.xyz += sin(_Time.y) * 0.1; // 随时间摆动(依赖模型空间)
    // ...
}

2. 使用多Pass Shader

多Pass Shader在批处理后可能导致渲染顺序异常。
示例场景

  • 双面渲染(一个Pass渲染正面,另一个Pass渲染背面)。
  • 复杂的后处理效果。
Tags { "DisableBatching" = "True" }
Pass {
    // 第一个Pass渲染正面
}
Pass {
    // 第二个Pass渲染背面
}

3. 使用GPU Instancing但需要实例ID

若Shader需要通过UNITY_VERTEX_INPUT_INSTANCE_ID获取实例ID(如为每个实例分配不同颜色),则必须禁用普通批处理,改用GPU Instancing。

Tags { "DisableBatching" = "True" } // 禁用普通批处理
#pragma multi_compile_instancing // 启用GPU Instancing
struct appdata {
    float4 vertex : POSITION;
    UNITY_VERTEX_INPUT_INSTANCE_ID // 声明实例ID
};

DisableBatching与性能

  • 禁用批处理的代价
    禁用批处理会增加Draw Call,可能降低性能。因此,应仅在必要时使用,并优先优化Shader逻辑。

  • 替代方案

    • GPU Instancing:若Shader支持,可通过#pragma multi_compile_instancing启用GPU Instancing,它允许在批处理的同时保留实例独立性。
    • 静态批处理:对于不移动的物体,Unity的静态批处理(Static Batching)可能不受DisableBatching影响。

常见应用场景

1. 顶点动画Shader

SubShader {
    Tags { "DisableBatching" = "True" }
    Pass {
        // 顶点动画代码(如草摆动、旗帜飘动)
    }
}

2. 多Pass透明度Shader

SubShader {
    Tags { 
        "DisableBatching" = "True" 
        "Queue" = "Transparent" 
    }
    Pass {
        // 渲染正面
    }
    Pass {
        // 渲染背面
    }
}

3. 基于实例ID的着色

SubShader {
    Tags { "DisableBatching" = "True" }
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    #pragma multi_compile_instancing
    
    struct appdata {
        float4 vertex : POSITION;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };
    
    UNITY_INSTANCING_BUFFER_START(Props)
        UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
    UNITY_INSTANCING_BUFFER_END(Props)
    
    v2f vert(appdata v) {
        UNITY_SETUP_INSTANCE_ID(v);
        float4 color = UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
        // 使用实例ID获取不同颜色
        // ...
    }
    ENDCG
}

最佳实践

  1. 仅在必要时禁用:优先调整Shader逻辑以支持批处理。
  2. 使用GPU Instancing:若需要实例独立性,优先启用GPU Instancing而非完全禁用批处理。
  3. 性能测试:禁用批处理后,使用Profiler检查Draw Call数量和渲染性能。

通过合理使用DisableBatching标签,可确保Shader功能正确的同时,尽可能减少性能开销。


4️⃣ForceNoShadowCasting

在Unity Shader中,ForceNoShadowCasting是一个用于控制阴影投射行为的标签。通过设置该标签,可以强制指定的物体不投射阴影,即使在光源设置中启用了阴影投射。以下是其作用、用法和注意事项:

ForceNoShadowCasting的作用

该标签的主要用途是:

  1. 强制禁用阴影投射:无论材质或光源如何设置,带有此标签的物体都不会投射阴影。
  2. 优化性能:对于不需要投射阴影的物体(如UI元素、粒子效果),禁用阴影投射可以减少计算开销。
  3. 解决阴影异常:某些特殊Shader(如使用复杂顶点动画的Shader)可能导致阴影计算错误,此时可禁用阴影投射。

标签语法

在SubShader中添加标签:

SubShader {
    Tags { "ForceNoShadowCasting" = "True" }
    // 其他Shader代码
}
  • True:强制禁用阴影投射。
  • False(默认):使用Unity的默认阴影投射规则。

应用场景

1. 不应该投射阴影的物体

// 粒子效果Shader
SubShader {
    Tags { 
        "Queue" = "Transparent" 
        "ForceNoShadowCasting" = "True" 
    }
    // 粒子渲染代码
}

2. UI元素或覆盖层

// UI Shader
SubShader {
    Tags { 
        "Queue" = "Overlay" 
        "ForceNoShadowCasting" = "True" 
    }
    // UI渲染代码
}

3. 动态物体的性能优化

对于频繁移动或变化的物体(如角色、特效),禁用阴影投射可以显著提升性能:

// 角色Shader(禁用阴影以优化性能)
SubShader {
    Tags { "ForceNoShadowCasting" = "True" }
    // 角色渲染代码
}

与其他阴影相关标签的区别

标签 作用
ForceNoShadowCasting 强制禁用阴影投射,无论光源和材质设置如何。
ShadowCaster Pass 自定义阴影投射的渲染逻辑(如使用不同的Shader)。
ReceiveShadows 控制物体是否接收阴影(而非投射阴影)。

注意事项

  1. 性能权衡

    • 禁用阴影投射可减少Draw Call和GPU计算,但可能影响场景真实感。
    • 对于静态物体,建议使用烘焙阴影而非动态阴影。
  2. 阴影接收
    ForceNoShadowCasting仅影响阴影投射,物体仍可接收其他物体的阴影。若需同时禁用阴影接收,可配合使用:

    Tags { 
        "ForceNoShadowCasting" = "True" 
        "ReceiveShadows" = "False" 
    }
    
  3. Shader替换
    在使用Shader替换(Shader Replacement)时,ForceNoShadowCasting标签可能被忽略,需在替换Shader中显式设置。

最佳实践

  1. 仅对必要物体禁用:优先为不影响视觉效果的物体(如UI、粒子)禁用阴影投射。
  2. 结合烘焙阴影:对于静态场景元素,使用光照贴图(Lightmap)和烘焙阴影可获得更好的性能。
  3. 性能测试:使用Unity Profiler检查阴影计算对性能的影响,针对性地优化。

通过合理使用ForceNoShadowCasting标签,可以在保证视觉效果的同时提升渲染性能,尤其在移动设备或性能敏感的场景中尤为重要。


5️⃣IgnoreProjector

在Unity Shader中,IgnoreProjector是一个用于控制Shader是否受Projector(投影器)影响的标签。通过设置该标签,可以让物体忽略场景中的投影器效果,保持自身原有渲染。以下是其作用、用法和注意事项:

IgnoreProjector的作用

Projector是Unity中用于投射纹理或效果的组件(如阴影、血迹、激光等)。但某些情况下,你可能希望特定物体不受投影器影响:

  1. 视觉一致性:确保物体渲染不受外部投影干扰(如UI元素、特效)。
  2. 性能优化:减少不必要的投影计算,提升性能。
  3. 技术限制:某些复杂Shader可能与投影器不兼容。

标签语法

在SubShader中添加标签:

SubShader {
    Tags { "IgnoreProjector" = "True" }
    // 其他Shader代码
}
  • True:物体将忽略所有投影器效果。
  • False(默认):物体将正常受投影器影响。

应用场景

1. UI元素或覆盖层

// UI Shader
SubShader {
    Tags { 
        "Queue" = "Overlay" 
        "IgnoreProjector" = "True" 
    }
    // UI渲染代码
}

2. 特效或粒子系统

// 粒子Shader
SubShader {
    Tags { 
        "Queue" = "Transparent" 
        "IgnoreProjector" = "True" 
    }
    // 粒子渲染代码
}

3. 已包含复杂效果的Shader

对于使用自定义光照模型或复杂顶点动画的Shader,投影器可能导致渲染异常:

// 自定义光照Shader
SubShader {
    Tags { "IgnoreProjector" = "True" }
    // 复杂光照计算代码
}

与其他标签的协同使用

标签 作用
IgnoreProjector 忽略投影器效果。
ForceNoShadowCasting 禁用阴影投射。
RenderType 控制Shader在特定场景(如延迟渲染)中的行为。

注意事项

  1. 投影器类型限制
    IgnoreProjector仅影响Unity的内置Projector组件,对基于脚本或后处理的自定义投影效果无效。

  2. 性能影响
    虽然忽略投影器可减少计算,但现代GPU处理投影器的开销通常较小,优化时需权衡。

  3. Shader替换
    在使用Shader替换(Shader Replacement)时,需确保替换Shader也包含IgnoreProjector标签。

最佳实践

  1. 仅对必要物体启用:优先为UI、特效等不需要投影效果的物体设置此标签。
  2. 测试视觉效果:禁用投影器可能影响场景真实感,需确保效果符合预期。
  3. 结合其他优化:与ForceNoShadowCasting、ReceiveShadows等标签配合使用,进一步减少渲染开销。

通过合理使用IgnoreProjector标签,可以确保特定物体的渲染效果不受投影器干扰,同时优化性能。


6️⃣CanUseSpriteAtlas

在Unity Shader中,CanUseSpriteAtlas 是一个与精灵图集(Sprite Atlas)相关的标签,主要用于控制Sprite是否可以从精灵图集中获取纹理数据。以下是其具体作用和用法:

CanUseSpriteAtlas的作用

精灵图集是Unity中优化2D渲染性能的重要工具,它将多个Sprite打包到一个或多个纹理中,减少Draw Call。CanUseSpriteAtlas 标签的核心作用是:

  1. 允许Sprite使用图集
    当标签设置为 "True" 时,Shader告诉Unity该Sprite可以从精灵图集中获取纹理数据。这是精灵图集正常工作的必要条件。

  2. 兼容Sprite Packer
    在旧版Unity(2017及之前)中,该标签用于与Sprite Packer系统配合,确保Sprite在打包后仍能正确渲染。

  3. 控制Shader替换行为
    在使用Shader替换(Shader Replacement)时,该标签可帮助Unity判断哪些Shader适用于精灵图集渲染。

标签语法

在Shader的SubShader中添加标签:

SubShader {
    Tags { "CanUseSpriteAtlas" = "True" }
    // 其他Shader代码
}
  • "True":允许Sprite使用精灵图集。
  • "False":禁用精灵图集支持,Sprite将始终使用单独的纹理。

应用场景

1. 精灵图集渲染

所有需要从精灵图集获取纹理的Sprite Shader都应添加此标签:

// 精灵Shader示例
SubShader {
    Tags { 
        "Queue" = "Transparent" 
        "IgnoreProjector" = "True" 
        "RenderType" = "Transparent" 
        "CanUseSpriteAtlas" = "True" 
    }
    // 渲染精灵的Pass
}

2. 自定义Sprite Shader

当创建自定义Sprite Shader时,必须添加此标签以确保与精灵图集兼容:

// 自定义精灵着色器
SubShader {
    Tags { "CanUseSpriteAtlas" = "True" }
    Pass {
        // 自定义渲染逻辑(如顶点动画、特殊效果)
    }
}

3. 旧版Unity兼容性

在Unity 2017及更早版本中,该标签对Sprite Packer系统至关重要:

// 兼容旧版Sprite Packer的Shader
SubShader {
    Tags { "CanUseSpriteAtlas" = "True" }
    // 旧版渲染逻辑
}

注意事项

  1. Unity版本差异

    • 在Unity 2018及以后,精灵图集系统(Sprite Atlas)已取代旧版Sprite Packer,但该标签仍需保留以确保兼容性。
    • 若Shader不打算用于精灵图集(如仅渲染单个Sprite),可将标签设为 "False"
  2. 与其他标签的协同
    通常需与以下标签共同使用:

    Tags {
        "RenderType" = "Transparent"
        "Queue" = "Transparent"
        "CanUseSpriteAtlas" = "True"
    }
    
  3. 性能影响
    使用精灵图集可显著减少Draw Call,提升2D渲染性能。若禁用该标签,Sprite将无法从图集中受益。

最佳实践

  1. 始终为精灵Shader添加此标签
    除非明确不需要使用精灵图集,否则所有Sprite Shader都应设置 "CanUseSpriteAtlas" = "True"

  2. 结合SpriteAtlas API
    在脚本中可通过 SpriteAtlas API 动态管理精灵图集:

    // C#示例:加载精灵图集
    SpriteAtlas atlas = Resources.Load<SpriteAtlas>("MySpriteAtlas");
    Sprite sprite = atlas.GetSprite("MySprite");
    
  3. 测试与优化
    使用Profiler检查精灵渲染的Draw Call数量,确保精灵图集正常工作。

通过合理使用 CanUseSpriteAtlas 标签,可确保Sprite在精灵图集中正确渲染,提升2D游戏的性能和兼容性。


7️⃣PreviewType

在Unity Shader中,PreviewType 是一个用于控制材质在Inspector面板中预览方式的标签。通过设置该标签,你可以自定义Shader在Unity编辑器中的预览效果,使其更直观地展示材质特性。以下是其作用、用法和常见场景:

PreviewType的作用

  1. 指定预览几何体
    控制Shader在Inspector面板中使用何种模型预览(如球体、立方体、平面等)。

  2. 自定义预览效果
    针对特殊Shader(如地形、UI、粒子),提供更符合其特性的预览方式。

  3. 优化预览性能
    对于复杂Shader,选择简单几何体可减少预览计算开销。

标签语法

在Shader代码中添加:

Shader "Custom/MyShader" {
    Properties {
        // 属性定义
    }
    SubShader {
        Tags { "PreviewType" = "Sphere" } // 指定预览类型
        // 其他Shader代码
    }
}

常见PreviewType值

作用
Sphere 使用球体预览(默认值,适合大多数Shader,如标准材质)。
Plane 使用平面预览(适合2D材质、UI元素、广告牌效果)。
Cube 使用立方体预览(适合立方体贴图、反射材质)。
Skybox 使用天空盒预览(适合天空盒Shader)。
Mesh 使用自定义网格预览(需配合 PreviewMesh 标签指定网格路径)。

应用场景

1. 2D精灵或UI材质

Shader "Custom/SpriteShader" {
    SubShader {
        Tags { 
            "PreviewType" = "Plane" // 使用平面预览,更符合2D材质特性
            "RenderType" = "Transparent"
        }
        // 渲染代码
    }
}

2. 立方体贴图或反射材质

Shader "Custom/ReflectionShader" {
    SubShader {
        Tags { 
            "PreviewType" = "Cube" // 使用立方体展示六个面的反射效果
        }
        // 渲染代码
    }
}

3. 天空盒Shader

Shader "Custom/SkyboxShader" {
    SubShader {
        Tags { 
            "PreviewType" = "Skybox" // 使用天空盒预览
            "RenderType" = "Background"
        }
        // 渲染代码
    }
}

4. 自定义网格预览

Shader "Custom/TerrainShader" {
    SubShader {
        Tags { 
            "PreviewType" = "Mesh"
            "PreviewMesh" = "Assets/Models/TerrainPreview.fbx" // 指定自定义网格
        }
        // 渲染代码
    }
}

与其他预览相关标签的配合

标签 作用
PreviewType 指定预览几何体类型。
PreviewMesh 当PreviewType为"Mesh"时,指定自定义网格的路径。
DisablePreview 禁用预览(设为"True"时,材质在Inspector中不显示预览)。

注意事项

  1. 性能考虑

    • 复杂网格(如自定义PreviewMesh)可能增加预览渲染时间,建议使用简化模型。
  2. 路径问题

    • 使用 PreviewMesh 时,需确保网格路径正确且可被Unity识别。
  3. 版本兼容性

    • 部分Unity版本可能对某些PreviewType值支持有限,建议测试后使用。

最佳实践

  1. 为特殊Shader指定合适类型

    • 2D材质 → Plane
    • 反射/立方体贴图 → Cube
    • 天空盒 → Skybox
    • 地形/复杂模型 → 自定义Mesh
  2. 简化自定义预览网格
    自定义PreviewMesh应尽量简单(如低面数模型),避免影响编辑器性能。

  3. 结合预览属性
    在Properties中添加预览相关属性(如预览颜色),提升可视化效果:

    Properties {
        _MainTex ("Texture", 2D) = "white" {}
        [PreviewVisible] _Color ("Preview Color", Color) = (1,1,1,1) // 预览可见的颜色
    }
    

通过合理设置 PreviewType,可以让Shader在Unity编辑器中更直观地展示其效果,提高开发效率。