3.5 材质 (Material) 与着色器 (Shader)


文档摘要

3.5 材质 (Material) 与着色器 (Shader) 3.5 材质 (Material) 与着色器 (Shader) 在 Unity3D 的世界中,材质 (Material) 与着色器 (Shader) 是构建视觉效果的核心基石。它们共同决定了游戏中物体的外观,从简单的颜色到复杂的光影效果,都离不开材质和着色器的精妙配合。理解材质和着色器的工作原理,是成为一名优秀的 Unity 开发者不可或缺的一步。 3.5.1 材质 (Material) 的概念与作用 什么是材质? 在现实世界中,材质描述了物体表面的物理属性,例如颜色、纹理、粗糙度、反射率等。这些属性决定了物体如何与光线相互作用,从而呈现出不同的外观。

3.5 材质 (Material) 与着色器 (Shader)

3.5 材质 (Material) 与着色器 (Shader)

在 Unity3D 的世界中,材质 (Material) 与着色器 (Shader) 是构建视觉效果的核心基石。它们共同决定了游戏中物体的外观,从简单的颜色到复杂的光影效果,都离不开材质和着色器的精妙配合。理解材质和着色器的工作原理,是成为一名优秀的 Unity 开发者不可或缺的一步。

3.5.1 材质 (Material) 的概念与作用

什么是材质?

在现实世界中,材质描述了物体表面的物理属性,例如颜色、纹理、粗糙度、反射率等。这些属性决定了物体如何与光线相互作用,从而呈现出不同的外观。

在 Unity3D 中,材质 (Material) 是资源的实例,它定义了如何渲染一个对象的外观。可以将材质视为一个“皮肤”,它被应用到 3D 模型上,赋予模型特定的视觉特征。材质包含了控制渲染过程的各种参数,例如颜色、纹理、光照属性等。

材质的作用:

  • 定义物体外观: 材质是控制物体最终视觉呈现的关键。通过调整材质的属性,可以改变物体的颜色、纹理、光泽度、透明度等,使其呈现出不同的质感和风格。

  • 控制渲染流程: 材质内部引用了着色器 (Shader),着色器是实际执行渲染计算的程序。材质通过向着色器传递参数,来控制着色器的行为,从而影响最终的渲染结果。

  • 资源复用与管理: 材质作为资源,可以在多个对象之间复用,节省资源并方便管理。例如,多个相同的木箱可以使用同一个木质材质,只需调整少量参数即可实现差异化。

  • 性能优化: 合理使用材质可以优化渲染性能。材质的属性设置和着色器的复杂度直接影响渲染的计算量。通过选择合适的着色器和优化材质参数,可以提高游戏的运行效率。

材质的组成部分:

一个材质主要由以下几个部分组成:

  • 着色器 (Shader): 材质的核心,决定了渲染算法和可调节的属性。每个材质都必须关联一个着色器。

  • 属性 (Properties): 着色器定义的、可以由材质实例控制的参数。例如颜色、纹理、数值等。材质通过调整这些属性的值来定制外观。

  • 纹理 (Textures): 图像数据,用于赋予材质更丰富的细节和视觉效果。例如颜色纹理、法线纹理、高光纹理等。

  • 颜色 (Colors): 用于定义材质的颜色属性,例如漫反射颜色、高光颜色、环境光颜色等。

  • 数值 (Numbers): 用于控制材质的数值属性,例如光滑度、金属度、透明度、反射强度等。

3.5.2 着色器 (Shader) 的概念与作用

什么是着色器?

着色器 (Shader) 是一种运行在 GPU (图形处理器) 上的程序,它负责计算如何渲染 3D 物体。更具体地说,着色器定义了渲染管线中特定阶段的处理逻辑,例如顶点着色器负责处理顶点数据,片元着色器(也称为像素着色器)负责处理像素颜色。

可以将着色器视为渲染的“算法”或“配方”,它告诉 GPU 如何将 3D 模型、材质属性、光照信息等转化为屏幕上的像素颜色。

着色器的作用:

  • 控制渲染管线: 着色器是渲染管线中不可或缺的组成部分。不同的着色器程序负责不同的渲染阶段,共同完成最终的渲染任务。

  • 实现视觉效果: 着色器是实现各种视觉效果的核心工具。通过编写不同的着色器代码,可以实现各种各样的渲染效果,例如卡通渲染、水面效果、火焰效果、体积云效果等。

  • 定义材质属性: 着色器定义了材质可以调节的属性。材质的属性面板实际上是由着色器定义的。

  • 性能优化: 着色器的性能直接影响渲染效率。编写高效的着色器代码,可以提高游戏的帧率,优化性能。

着色器的类型:

Unity 中常用的着色器类型包括:

  • 表面着色器 (Surface Shader): Unity 提供的简化着色器编写方式,隐藏了复杂的渲染细节,适合快速实现常见的光照模型。

  • 顶点片元着色器 (Vertex/Fragment Shader): 也称为 ShaderLab 程序,是最灵活、功能最强大的着色器类型,可以完全自定义渲染管线的各个阶段。

  • 固定功能管线着色器 (Fixed Function Shader): 较旧的着色器类型,功能有限,现在已经较少使用。

  • 计算着色器 (Compute Shader): 用于通用计算的着色器,不直接参与渲染,但可以用于 GPU 加速的计算任务。

本章节主要关注 顶点片元着色器 (Vertex/Fragment Shader),因为它提供了最大的灵活性和控制力,是理解着色器原理的基础。

3.5.3 材质与着色器的关系

材质和着色器是紧密相关的,它们之间的关系可以理解为:

  • 着色器是蓝图,材质是实例: 着色器定义了渲染逻辑和可调节的属性,而材质是基于某个着色器创建的实例。一个着色器可以被多个材质复用。

  • 材质驱动着色器: 材质通过设置属性值,来控制着色器的行为。材质的属性值会传递给着色器,作为着色器计算的输入参数。

  • 着色器决定材质的功能: 材质的功能和可调节的属性完全由其关联的着色器决定。更换材质的着色器,材质的功能和外观也会随之改变。

可以用一个比喻来形象地理解它们的关系:

关系图解释:

  1. Shader (着色器) 是核心,它定义了渲染的规则和可以调节的属性。

  2. Material (材质) 基于 Shader 创建,是 Shader 的一个具体实例。

  3. Shader 定义了材质可以有哪些属性,例如颜色、纹理等。

  4. Material 负责设置这些属性的具体数值,例如颜色设置为红色,纹理设置为木纹图片。

  5. Material 被应用到 3D 对象上,最终决定了对象的渲染外观。

  6. 当渲染时,Material 将其属性值传递给 Shader,Shader 根据这些属性值和自身的渲染逻辑进行计算,最终输出对象的像素颜色。

3.5.4 Unity 中的材质与着色器实践

1. 创建材质 (Material)

在 Unity 编辑器中,创建材质非常简单:

  • Project 窗口 中,右键单击,选择 Create > Material

  • 输入材质的名称,例如 "MyMaterial"。

  • Inspector 窗口 中,可以看到材质的属性面板。

2. 选择着色器 (Shader)

  • 在材质的 Inspector 窗口 中,点击 Shader 下拉菜单

  • 可以看到 Unity 内置的各种着色器,以及项目中自定义的着色器。

  • 选择合适的着色器,例如 "Standard" (标准着色器) 或 "Unlit/Color" (无光照颜色着色器)。

3. 调整材质属性

  • 选择了着色器后,材质的 Inspector 窗口 会显示该着色器定义的属性。

  • 例如,如果选择了 "Standard" 着色器,可以看到 "Albedo" (反照率颜色)、 "Metallic" (金属度)、 "Smoothness" (光滑度) 等属性。

  • 可以通过颜色拾取器、纹理选择器、数值输入框等方式,调整这些属性的值,实时预览材质的外观变化。

代码示例 1:创建并修改材质 (C# Script)

using UnityEngine; public class MaterialExample : MonoBehaviour { public Renderer targetRenderer; // 目标渲染器 void Start() { if (targetRenderer == null) { Debug.LogError("请将 Renderer 组件拖拽到 Target Renderer 字段!"); return; } // 1. 创建一个新的材质实例 (基于 Renderer 当前使用的材质) Material newMaterial = new Material(targetRenderer.sharedMaterial); // 2. 修改材质的颜色属性 (假设 Shader 中定义了 "_Color" 属性) newMaterial.color = Color.blue; // 设置为蓝色 newMaterial.SetColor("_Color", Color.yellow); // 或者使用 SetColor,参数为属性名和颜色值 // 3. 修改材质的浮点数属性 (假设 Shader 中定义了 "_Glossiness" 属性) newMaterial.SetFloat("_Glossiness", 0.8f); // 4. 修改材质的纹理属性 (假设 Shader 中定义了 "_MainTex" 属性) Texture2D texture = Resources.Load<Texture2D>("MyTexture"); // 从 Resources 文件夹加载纹理 if (texture != null) { newMaterial.SetTexture("_MainTex", texture); } else { Debug.LogWarning("纹理 'MyTexture' 未找到!"); } // 5. 将新的材质实例应用到 Renderer targetRenderer.material = newMaterial; // 注意使用 .material 会创建材质的实例,.sharedMaterial 会共享材质 } }

代码解释:

  1. new Material(targetRenderer.sharedMaterial): 创建一个新的材质实例,并复制 targetRenderer 当前使用的共享材质的属性。这样做可以避免修改共享材质,影响到其他使用该材质的对象。

  2. newMaterial.color = Color.blue;: 直接修改材质的 color 属性 (如果 Shader 中有定义)。

  3. newMaterial.SetColor("_Color", Color.yellow);: 更通用的方法,使用 SetColor 函数,参数为 Shader 中定义的属性名称 ("_Color") 和颜色值。

  4. newMaterial.SetFloat("_Glossiness", 0.8f);: 使用 SetFloat 函数修改浮点数属性。

  5. newMaterial.SetTexture("_MainTex", texture);: 使用 SetTexture 函数修改纹理属性。

  6. targetRenderer.material = newMaterial;: 将新创建的材质实例赋值给 targetRenderer.material。注意这里使用 material 属性会为每个渲染器创建一个独立的材质实例,而 sharedMaterial 会共享材质,修改 sharedMaterial 会影响所有使用该材质的渲染器。

4. 创建着色器 (Shader)

在 Unity 中,可以通过以下方式创建着色器:

  • Project 窗口 中,右键单击,选择 Create > Shader > Standard Surface Shader (表面着色器) 或 Create > Shader > Unlit Shader (无光照着色器) 或 Create > Shader > ShaderLab > Standard Shader (Built-in Render Pipeline) (顶点片元着色器)。

  • 输入着色器的名称,例如 "MyShader"。

  • 双击打开着色器文件,使用文本编辑器 (例如 Visual Studio Code) 编辑着色器代码。

代码示例 2:一个简单的无光照颜色着色器 (ShaderLab)

Shader "Unlit/SimpleColorShader" { Properties { _Color ("Main Color", Color) = (1,1,1,1) // 定义一个颜色属性,默认白色 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 vertex : SV_POSITION; }; fixed4 _Color; // 声明与 Properties 中属性对应的变量 v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); return o; } fixed4 frag (v2f i) : SV_Target { return _Color; // 输出材质的颜色属性 } ENDCG } } }

代码解释:

  • Shader "Unlit/SimpleColorShader": 定义着色器的路径和名称,在材质的 Shader 下拉菜单中会显示 "Unlit/SimpleColorShader"。

  • Properties: 定义着色器可以调节的属性。

    • _Color ("Main Color", Color) = (1,1,1,1): 定义一个名为 _Color 的颜色属性,显示名称为 "Main Color",类型为 Color,默认值为白色 (1,1,1,1)。
  • SubShader: 定义一个或多个 SubShader,Unity 会根据平台和硬件选择合适的 SubShader。

    • Tags { "RenderType"="Opaque" }: 设置渲染类型为不透明 (Opaque)。

    • LOD 100: 设置 LOD (Level of Detail) 级别。

    • Pass: 定义一个渲染通道,一个 SubShader 可以包含多个 Pass。

      • CGPROGRAM ... ENDCG: 包含 CG/HLSL 代码块。

      • #pragma vertex vert: 声明顶点着色器函数为 vert

      • #pragma fragment frag: 声明片元着色器函数为 frag

      • #include "UnityCG.cginc": 包含 Unity 预定义的 CG/HLSL 头文件,提供常用的宏和函数。

      • struct appdata: 定义顶点着色器输入结构体,包含顶点位置 vertex : POSITION

      • struct v2f: 定义顶点着色器输出结构体 (Vertex to Fragment),包含裁剪空间顶点位置 vertex : SV_POSITION

      • fixed4 _Color;: 在 CGPROGRAM 块中声明一个与 Properties_Color 属性同名的变量,用于接收材质传递的属性值。

      • v2f vert (appdata v): 顶点着色器函数。

        • o.vertex = UnityObjectToClipPos(v.vertex);: 将模型空间顶点坐标转换为裁剪空间坐标。
      • fixed4 frag (v2f i) : SV_Target: 片元着色器函数。

        • return _Color;: 返回材质的颜色属性 _Color 作为像素颜色。

5. 将着色器应用到材质

  • 创建材质后,在材质的 Inspector 窗口 中,点击 Shader 下拉菜单

  • 在下拉菜单中,找到并选择你创建的着色器,例如 "Unlit/SimpleColorShader"。

  • 材质的属性面板会更新,显示着色器定义的属性,例如 "Main Color"。

  • 调整 "Main Color" 属性,可以看到应用该材质的物体的颜色随之改变。

6. 材质实例与共享材质

在 Unity 中,材质分为 实例材质 (Instance Material)共享材质 (Shared Material)

  • 实例材质 (Instance Material): 每个 Renderer 组件的 material 属性返回的是材质的实例。修改实例材质只会影响该 Renderer 组件,不会影响其他对象。Unity 会在运行时为每个 Renderer 创建独立的材质实例,以支持不同的材质属性设置。

  • 共享材质 (Shared Material): Renderer 组件的 sharedMaterial 属性返回的是共享材质。修改共享材质会影响所有使用该材质的对象。共享材质通常用于多个对象共享相同材质的情况,可以节省内存。

何时使用实例材质,何时使用共享材质?

  • 修改单个对象的材质: 使用 renderer.material 创建或修改材质实例。这是最常用的情况,例如为每个角色设置不同的颜色。

  • 修改多个对象的共享材质: 使用 renderer.sharedMaterial 获取共享材质,并进行修改。需要谨慎使用,因为会影响所有使用该材质的对象。通常用于全局性的材质修改,例如改变所有物体的环境光颜色。

  • 创建新的材质实例: 使用 new Material(sharedMaterial) 基于共享材质创建一个新的实例材质。

性能考虑:

  • 材质实例化 (Material Instancing): Unity 提供了材质实例化技术,可以有效地减少 Draw Call (绘制调用) 次数,提高渲染性能。当多个对象使用相同的材质,但只有少量属性不同时,可以使用材质实例化。Unity 会将这些对象的绘制合并成一个 Draw Call。

  • Shader 复杂度: 复杂的 Shader 会增加 GPU 的计算负担,降低渲染性能。应根据实际需求选择合适的 Shader 复杂度,避免过度使用复杂的 Shader 效果。

  • 纹理大小和数量: 纹理的加载和采样也会影响性能。应优化纹理大小和数量,尽量使用压缩纹理格式,并合理使用纹理图集 (Texture Atlas)。

3.5.5 总结

材质 (Material) 与着色器 (Shader) 是 Unity3D 渲染系统的核心组成部分。材质定义了物体的外观属性,着色器则定义了渲染算法。理解它们之间的关系和工作原理,是掌握 Unity 渲染技术的基础。

通过本章节的学习,您应该掌握了以下知识点:

  • 材质和着色器的概念和作用。

  • 材质与着色器的关系:着色器是蓝图,材质是实例。

  • 如何在 Unity 中创建和修改材质。

  • 如何创建简单的顶点片元着色器。

  • 材质实例和共享材质的区别和使用场景。

  • 材质和着色器的性能优化 considerations.

深入理解材质和着色器,并灵活运用它们,将帮助您在 Unity 项目中创建出更加精美、高效的视觉效果,提升游戏的品质和用户体验。希望本章节的内容能够为您在 Unity 渲染技术的学习之路上提供有力的帮助。

后续学习方向:

  • 深入学习 ShaderLab 语言和 CG/HLSL 编程: 掌握着色器代码的编写,才能真正自定义渲染效果。

  • 研究 Unity 内置的各种 Shader 和光照模型: 了解 Unity 提供的渲染工具和技术。

  • 学习 Shader Graph 可视化着色器编辑器: 使用可视化工具快速创建复杂的着色器效果。

  • 探索高级渲染技术: 例如延迟渲染、后处理效果、体积渲染、光线追踪等。

祝您在 Unity 渲染技术的学习中取得更大的进步!


发布者: 作者: 转发
评论区 (0)
U