Unity引擎材质系统解析原理

Unity引擎材质系统解析原理


一、核心架构

Unity材质系统围绕**PBR(物理基础渲染)**设计,主要分为三大层级:

  1. 材质资产层(Material Asset)

    • 存储Shader引用、参数(颜色、数值、贴图)、渲染队列、渲染状态(如混合、剔除、ZTest等)。
    • .mat文件形式存在,序列化在项目资源中。
    • 关联Shader文件(如Standard、URP/Lit等)。
  2. 材质实例层(Material Instance)

    • 运行时可通过Material对象动态修改参数(如SetFloatSetTexture)。
    • 支持MaterialPropertyBlock,实现同一材质资产下的批量实例化和参数差异化,避免材质资产冗余。
    • 支持运行时克隆(new Material(mat)),便于动态效果。
  3. 着色器编译层(Shader Compilation)

    • 材质参数和功能开关(如是否有法线贴图、金属贴图)决定Shader变体。
    • Unity自动管理Shader变体编译、缓存和运行时切换。
    • 支持多平台后端(GLSL/HLSL/Metal等)。

二、核心参数体系

参数类型作用原理数据范围/格式
Albedo表面基础色,决定物体主色调RGB(0-1)
Metallic金属度,0为绝缘体,1为金属0.0-1.0
Smoothness光滑度,控制高光锐利度(与Roughness反向)0.0-1.0
Occlusion环境光遮蔽,控制AO强度单通道(0-1)
Normal Map法线贴图,存储切线空间法线RGB,标准化向量
Emission自发光,决定物体自发光颜色RGB(0-1)
Specular高光颜色(镜面工作流专用)RGB(0-1)
  • 金属工作流:Albedo+Metallic+Smoothness为主,贴图通常合并(如Metallic®+Smoothness(A))。
  • 镜面工作流:Albedo+Specular+Smoothness,Specular为高光颜色贴图。

三、工作流实现

1. 金属工作流(Metallic Workflow)

  • 核心特征:Albedo为基础色,金属度决定能否反射环境,Smoothness控制高光锐度。

  • 贴图合并:通常Metallic和Smoothness合并为一张贴图(R通道金属度,A通道光滑度)。

  • Shader片段示例(Unity Standard):

    half metallic = tex2D(_MetallicGlossMap, uv).r * _Metallic;
    half smoothness = _GlossMapScale * tex2D(_MetallicGlossMap, uv).a;
    half3 diffuse = lerp(albedo, 0, metallic);
    half3 specular = lerp(0.04, albedo, metallic);
    // 光照计算
    

2. 镜面工作流(Specular Workflow)

  • 核心特征:Specular贴图直接定义高光颜色,适合非金属有色高光材质。

  • Shader片段示例

    half4 specGloss = tex2D(_SpecGlossMap, uv);
    half3 specular = specGloss.rgb * _SpecColor.rgb;
    half smoothness = _GlossMapScale * specGloss.a;
    // 能量守恒计算
    

四、渲染流程实现

1. 材质实例化与参数修改

  • 运行时修改Material.SetFloatSetTextureSetColor等。
  • 批量实例化MaterialPropertyBlock,用于同一材质资产下的参数差异化,提升批量渲染效率。
  • 动态克隆new Material(originalMat),避免影响原始资产。

2. Shader变体管理

  • 功能开关#pragma shader_feature#pragma multi_compile,如_NORMALMAP_METALLICGLOSSMAP
  • 变体编译:Unity自动根据材质参数和功能开关生成、缓存、切换Shader变体。
  • 变体剔除:通过ShaderVariantCollectionGraphicsSettings优化构建体积。

3. 渲染路径适配

  • 前向渲染:每像素最多支持4个实时光源,超出部分以逐顶点或球谐光处理。
  • 延迟渲染:所有光源信息写入GBuffer,Lighting Pass统一处理,理论支持无限光源。

五、核心优化机制

1. 能量守恒

  • 原理:漫反射+镜面反射能量不超过入射光能量,避免材质过曝。
  • 实现diffuse + specular <= 1.0,Shader中通过lerp和归一化实现。

2. 菲涅尔效应

  • 原理:视角越斜,反射越强,提升真实感。

  • 实现(Unity内置近似):

    half fresnel = pow(1.0 - saturate(dot(normal, viewDir)), 5.0);
    specular *= 1.0 + fresnel * (1.0 / max(specular, 0.001) - 1.0);
    

3. 多光源支持

  • 前向渲染:主光源+最多3个附加光源逐像素,超出部分逐顶点或球谐光。
  • 延迟渲染:所有光源信息写入GBuffer,Lighting Pass统一处理,理论支持无限光源。

六、底层实现与源码参考

  • 材质与Shader绑定Material对象持有Shader引用,参数通过PropertyID映射到GPU常量缓冲区。
  • 参数传递:C#层Material.SetXXX → C++层GfxDevice::SetMaterialProperty → GPU Uniform/CBV/UBO。
  • 变体切换:C#层Material.EnableKeyword/DisableKeyword,底层自动切换对应变体。
  • SRP适配:URP/HDRP通过MaterialPropertyBlockShaderTagId实现灵活调度。

七、参考资料

  1. Unity官方文档-材质系统
  2. Unity官方文档-标准着色器
  3. Unity官方文档-Shader变体
  4. Unity C#源码(Material/Shader)
  5. Unity SRP源码(URP/HDRP)
  6. PBR原理与能量守恒
  7. Unity Standard Shader源码

八、总结

  • Unity材质系统以PBR为核心,分为资产、实例、编译三层,支持灵活参数管理和高效批量渲染。
  • 支持金属/镜面两种主流工作流,参数体系与物理模型紧密结合。
  • 通过Shader变体、能量守恒、菲涅尔效应等机制,兼顾真实感与性能。
  • 适配多种渲染路径和平台,底层实现高度自动化,便于开发者高效使用。

下面将结合Unity C#源码、Shader源码和底层流程,分层次给出Unity引擎材质系统的核心源码解析。内容涵盖:

  1. C#层材质与Shader绑定、参数管理源码
  2. ShaderLab层参数声明与映射
  3. 底层参数传递与变体切换流程
  4. SRP材质系统关键源码(以URP为例)
  5. 参考与说明

1. C#层材质与Shader绑定、参数管理源码

1.1 材质与Shader绑定

Material.cs(UnityCsReference)
Material.cs 源码

public class Material : Object
{
    public Material(Shader shader) { /* 绑定Shader */ }
    public Material(Material source) { /* 克隆材质 */ }

    public Shader shader { get; set; }
    // ...
}

用法示例:

Shader shader = Shader.Find("Standard");
Material mat = new Material(shader);

1.2 材质参数管理

public void SetFloat(string name, float value);
public void SetColor(string name, Color value);
public void SetTexture(string name, Texture value);
public void SetVector(string name, Vector4 value);
public void SetMatrix(string name, Matrix4x4 value);

底层实现:
参数通过Shader.PropertyToID(name)转为int,映射到GPU常量缓冲区。

示例:

mat.SetFloat("_Metallic", 0.8f);
mat.SetTexture("_MainTex", tex);

1.3 MaterialPropertyBlock支持

MaterialPropertyBlock.cs
MaterialPropertyBlock.cs 源码

MaterialPropertyBlock block = new MaterialPropertyBlock();
block.SetFloat("_Metallic", 0.5f);
renderer.SetPropertyBlock(block);
  • 用于批量渲染时的参数差异化,避免实例化新材质。

2. ShaderLab层参数声明与映射

标准Shader参数声明:

Shader "Standard"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo", 2D) = "white" {}
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
    }
    SubShader
    {
        CGPROGRAM
        // 声明与Properties一致
        float4 _Color;
        sampler2D _MainTex;
        float _Metallic;
        float _Glossiness;
        // ...
        ENDCG
    }
}
  • C#层SetFloat("_Metallic", ...)会自动映射到Shader中的_Metallic变量。

3. 底层参数传递与变体切换流程

3.1 参数传递流程

  1. C#层调用SetFloat等,参数存入Material的C++对象。
  2. 渲染时,Unity将参数打包为Uniform Buffer(CBV/UBO),通过底层API(如glUniformvkUpdateDescriptorSets)上传到GPU。
  3. Shader中通过变量名直接访问。

3.2 Shader变体切换

声明:

#pragma shader_feature _NORMALMAP
#pragma shader_feature _METALLICGLOSSMAP
  • 材质启用/禁用功能时,C#层调用EnableKeyword("_NORMALMAP"),Unity自动切换对应变体。

C#源码片段:

public void EnableKeyword(string keyword);
public void DisableKeyword(string keyword);

底层流程:

  • Unity内部维护变体哈希表,按当前启用的Keyword查找/切换Shader变体。

4. SRP材质系统关键源码(以URP为例)

4.1 材质参数传递

URP/Lit.shader(部分)

CBUFFER_START(UnityPerMaterial)
    float4 _BaseColor;
    float4 _BaseMap_ST;
    float _Cutoff;
    float _Smoothness;
    float _Metallic;
    // ...
CBUFFER_END
  • SRP下参数通过CBUFFER(常量缓冲区)传递,支持高效批量渲染。

4.2 渲染流程(URP)

UniversalRenderPipeline.cs(核心片段)

foreach (var renderer in renderers)
{
    // 绑定材质参数
    context.SetupCameraProperties(camera);
    // 绘制物体
    context.DrawRenderers(cullResults, ref drawingSettings, ref filteringSettings);
}
  • drawingSettings中包含材质、ShaderTagId、Keyword等信息。

5. 参考与说明


总结

  • C#层:Material对象绑定Shader,参数通过SetXXX接口传递,支持PropertyBlock批量优化。
  • ShaderLab层:Properties声明参数,自动与C#层映射,支持变体声明。
  • 底层:参数打包为Uniform Buffer上传,变体通过Keyword切换。
  • SRP:参数通过CBUFFER高效传递,渲染流程高度模块化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

你一身傲骨怎能输

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

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

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

打赏作者

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

抵扣说明:

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

余额充值