> 技术文档 > 第3章 掌握Unity着色器:从ShaderLab到顶点/片元着色器的全面指南

第3章 掌握Unity着色器:从ShaderLab到顶点/片元着色器的全面指南


掌握Unity着色器:从ShaderLab到顶点/片元着色器的全面指南

3.1 Unity Shader 概述

着色器(Shader)是现代游戏开发中实现视觉效果的核心技术。在Unity引擎中,着色器系统以其独特的架构提供了强大而灵活的图形渲染能力。本章将全面探讨Unity着色器的基础知识,帮助开发者理解如何有效地创建和应用着色器。

3.1.1 材质和 Unity Shader

在Unity的渲染系统中,材质(Material)和着色器(Shader)紧密合作,共同决定游戏对象的外观。它们的关系可以类比为\"烹饪\":着色器是\"食谱\",定义了渲染的算法和步骤;而材质则是\"实际的菜肴\",它根据着色器的定义,结合具体的参数值(如纹理、颜色等),呈现最终的视觉效果。

这种关系具有以下特点:

  1. 一对多关系:一个着色器可以被多个材质使用,每个材质可以有不同的参数配置
  2. 参数化控制:着色器定义参数,材质提供具体值
  3. 可视化编辑:材质通过Inspector窗口提供直观的参数调整界面

csharp

// 在运行时创建和配置材质与着色器的关系using UnityEngine;public class ShaderMaterialRelationship : MonoBehaviour{ public Shader customShader; // 在Inspector中指定自定义着色器 void Start() { // 检查着色器是否可用 if (customShader == null) { Debug.LogError(\"请指定一个着色器!\"); return; } // 创建一个使用指定着色器的新材质 Material newMaterial = new Material(customShader); // 设置材质参数 newMaterial.SetColor(\"_Color\", Color.red); newMaterial.SetFloat(\"_Glossiness\", 0.7f); newMaterial.SetTexture(\"_MainTex\", Resources.Load(\"DefaultTexture\")); // 将材质应用到当前对象 Renderer renderer = GetComponent(); if (renderer != null) { renderer.material = newMaterial; Debug.Log(\"成功应用新材质,使用着色器: \" + customShader.name); } } // 演示如何在运行时修改材质参数而不改变着色器 void Update() { Renderer renderer = GetComponent(); if (renderer != null && renderer.material != null) { // 随时间变化颜色 float t = Mathf.PingPong(Time.time, 1.0f); Color lerpedColor = Color.Lerp(Color.red, Color.blue, t); renderer.material.SetColor(\"_Color\", lerpedColor); } }}

3.1.2 Unity 中的材质

Unity中的材质是一个具体的资源,它存储了渲染一个对象所需的所有信息:

  • 使用哪个着色器
  • 着色器参数的具体值(颜色、纹理、数值等)
  • 渲染状态设置(如混合模式、深度测试等)

材质可以通过多种方式创建:

  1. 在Project窗口中右键选择Create > Material
  2. 通过脚本动态创建(如上例所示)
  3. 从Asset Store导入

csharp

// 展示材质的常见操作using UnityEngine;public class MaterialOperations : MonoBehaviour{ public Material sourceMaterial; // 基础材质 private Material instancedMaterial; // 实例化的材质 void Start() { // 实例化材质以避免修改原始资源 instancedMaterial = new Material(sourceMaterial); GetComponent().material = instancedMaterial; // 演示材质属性访问方法 DemonstratePropertyAccess(); } void DemonstratePropertyAccess() { // 检查材质是否有特定属性 if (instancedMaterial.HasProperty(\"_Color\")) { Debug.Log(\"材质有_Color属性\"); } // 不同类型属性的获取和设置 // 颜色 Color currentColor = instancedMaterial.GetColor(\"_Color\"); instancedMaterial.SetColor(\"_Color\", new Color(1, 0, 0, 0.5f)); // 浮点数 float smoothness = instancedMaterial.GetFloat(\"_Glossiness\"); instancedMaterial.SetFloat(\"_Glossiness\", 0.8f); // 向量 Vector4 tilingOffset = instancedMaterial.GetVector(\"_MainTex_ST\"); instancedMaterial.SetVector(\"_MainTex_ST\", new Vector4(2, 2, 0, 0)); // 2x缩放,无偏移 // 纹理 Texture mainTex = instancedMaterial.GetTexture(\"_MainTex\"); instancedMaterial.SetTexture(\"_MainTex\", Resources.Load(\"NewTexture\")); // 整数 int intValue = instancedMaterial.GetInt(\"_IntProperty\"); instancedMaterial.SetInt(\"_IntProperty\", 5); // 设置关键字 - 用于条件编译 instancedMaterial.EnableKeyword(\"_EMISSION\"); instancedMaterial.DisableKeyword(\"_NORMALMAP\"); // 渲染队列 instancedMaterial.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; } void OnDestroy() { // 清理实例化的材质 if (instancedMaterial != null) { // 在编辑器中 #if UNITY_EDITOR DestroyImmediate(instancedMaterial); #else // 在运行时 Destroy(instancedMaterial); #endif } }}

3.1.3 Unity 中的 Shader

Unity中的Shader是定义渲染逻辑的程序。与传统的着色器语言不同,Unity使用了一种名为ShaderLab的专有语言来声明着色器。ShaderLab封装了传统着色器代码(通常是CG/HLSL),并提供了额外的元数据和配置信息。

Unity着色器的主要功能包括:

  • 定义材质在Inspector中显示的属性
  • 指定渲染设置(如混合模式、深度测试等)
  • 包含顶点和片元着色器的实际代码
  • 定义多种渲染路径的处理方法(如前向渲染、延迟渲染)
  • 指定回退着色器(当当前着色器不支持时使用)

glsl

// Unity中一个基本的着色器示例Shader \"Custom/BasicShader\"{ // 定义在Inspector中显示的属性 Properties { _MainTex (\"Texture\", 2D) = \"white\" {} _Color (\"Color\", Color) = (1,1,1,1) _Glossiness (\"Smoothness\", Range(0,1)) = 0.5 _Metallic (\"Metallic\", Range(0,1)) = 0.0 } // 子着色器 - 为不同图形API和硬件定义不同实现 SubShader { // 渲染设置 Tags { \"RenderType\"=\"Opaque\" \"Queue\"=\"Geometry\" } LOD 200 // CG/HLSL代码块 CGPROGRAM // 编译指令 #pragma surface surf Standard fullforwardshadows #pragma target 3.0 // 输入结构体 struct Input { float2 uv_MainTex; }; // 属性变量 sampler2D _MainTex; fixed4 _Color; half _Glossiness; half _Metallic; // 表面着色器函数 void surf (Input IN, inout SurfaceOutputStandard o) { // 从纹理采样并应用颜色 fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } ENDCG } // 回退着色器 FallBack \"Diffuse\"}

3.2 Unity Shader 的基础: ShaderLab

ShaderLab是Unity特有的着色器声明语言,它为传统着色器提供了一层封装,使着色器更容易集成到Unity的渲染系统中。ShaderLab的主要目的是提供一个统一的框架,用于定义着色器的各个方面,包括属性、渲染状态和多平台支持。

ShaderLab的主要组成部分包括:

  1. Shader块:整个着色器的容器,包含名称和所有内容
  2. Properties块:定义在Inspector中可编辑的属性
  3. SubShader块:包含一个或多个渲染通道(Pass)的实现
  4. Pass块:定义单次渲染通道的具体设置和代码
  5. 回退机制:指定当当前SubShader不支持时使用的替代着色器

下面是一个ShaderLab基础结构的示例:

glsl

// ShaderLab基础结构示例Shader \"Custom/ShaderLabBasics\"{ // 属性块 - 定义在Inspector中显示的参数 Properties { _MainTex (\"Albedo (RGB)\", 2D) = \"white\" {} _Color (\"Color\", Color) = (1,1,1,1) _Glossiness (\"Smoothness\", Range(0,1)) = 0.5 _Metallic (\"Metallic\", Range(0,1)) = 0.0 [Toggle] _UseSpecular (\"Use Specular\", Float) = 0 [KeywordEnum(None, Add, Multiply)] _Overlay (\"Overlay Mode\", Float) = 0 [PowerSlider(3.0)] _SpecPower (\"Specular Power\", Range(0.01, 50)) = 1 [IntRange] _Samples (\"Sample Count\", Range(1, 32)) = 16 [Header(Normal Mapping)] _BumpMap (\"Normal Map\", 2D) = \"bump\" {} [Space(20)] [Enum(UnityEngine.Rendering.CullMode)] _Cull (\"Culling\", Float) = 2 } // 子着色器块 - 可以有多个,按顺序尝试使用 SubShader { // 标签 - 影响着色器如何被Unity的渲染系统处理 Tags { \"RenderType\" = \"Opaque\" \"Queue\" = \"Geometry\" \"DisableBatching\" = \"False\" \"ForceNoShadowCasting\" = \"False\" \"IgnoreProjector\" = \"False\" } // LOD级别 - 控制着色器的复杂度,用于LOD系统 LOD 300 // 全局渲染状态设置 Cull [_Cull] // 使用属性中定义的剔除模式 ZWrite On // 启用深度写入 ZTest LEqual // 深度测试模式 Blend One Zero // 混合模式 // 第一个通道 Pass { Name \"FORWARD\" Tags { \"LightMode\" = \"ForwardBase\" } // 通道特定的渲染状态设置(可选) // Cull, ZWrite, ZTest, Blend等可以在这里重新定义 // CG/HLSL代码 CGPROGRAM #pragma vertex vert #pragma fragment frag // 编译指令... // 着色器代码... ENDCG } // 可以定义更多通道... } // 可以定义更多子着色器... // 回退着色器 FallBack \"Standard\" // 自定义编辑器(可选) CustomEditor \"CustomShaderGUI\"}

ShaderLab提供了许多内置功能,使着色器开发更加便捷:

  1. 属性装饰器

    • [Header], [Space] - 改善Inspector布局
    • [Toggle], [Enum], [KeywordEnum] - 创建特殊UI控件
    • [PowerSlider], [IntRange] - 自定义数值范围控件
    • [HDR], [Gamma] - 特殊颜色处理
  2. 渲染状态命令

    • Cull - 控制多边形剔除
    • ZWrite, ZTest - 深度缓冲区控制
    • Blend - 混合模式设置
    • Stencil - 模板缓冲区操作
    • ColorMask - 控制颜色通道写入