【从UnityURP开始探索游戏渲染】专栏-直达

漫反射辐照的核心作用

漫反射辐照(Diffuse Irradiance)在URP PBR中用于模拟环境光对物体表面的均匀散射效果,通过预计算环境立方体贴图的低频光照信息,为动态物体提供间接漫反射光照。其核心公式为:

$L_d=\frac{c}{\pi}\int_\Omega L_i(\omega_i)(n\cdot\omega_i)d\omega_i$

其中c为反照率,$L_i$为环境光强度。

其核心是将环境立方体贴图卷积为球谐系数(SH)或光照探针数据。计算过程遵循Lambertian反射模型.

技术演进关键节点

  • Unity 5.x时代

    首次引入标准PBR管线,但依赖内置渲染管线,环境光计算需全分辨率立方体贴图,内存消耗大。

  • URP 7.x 2020

    采用三层球谐基函数压缩环境光数据,内存占用降低90%以上,同时支持动态光照探针混合,实现移动端高效运行。

  • URP 2022

    引入HDR环境贴图支持,提升高动态范围场景下漫反射辐照的精度,通过RGBM编码解决LDR贴图亮度失真问题。

解决的问题与方案优势

传统问题

  • 动态物体无法复用静态光照贴图,导致场景光照不连贯。
  • 实时积分计算环境光性能开销过高,尤其在移动端。

URP方案选择原因

  • 球谐函数压缩‌:用9个系数(三层SH)近似环境光分布,相比立方体贴图减少90%内存占用。

    球谐系数(SH)卷积计算原理

    • 环境立方体贴图到球谐系数的转换过程分为两步:

      • 首先对立方体贴图进行蒙特卡洛积分,计算各阶球谐基函数的投影系数;
      • 然后在运行时通过法线向量重建光照。
    • 核心公式为:

    $c_{l,m}=\int_\Omega L_i(\omega)Y_{l,m}(\omega)d\omega$

    其中$Y_{l,m}$为球谐基函数,$L_i$为环境光强度。Unity采用三阶SH(9个系数),仅需存储RGB三个通道的9个浮点数,相比立方体贴图内存占用减少99.8%。

    具体实现步骤

    • 预计算阶段

      对立方体贴图的每个纹素进行半球积分,计算0-2阶球谐系数:

      hlsl
      // 伪代码:立方体贴图投影到SH
      for each texel in cubemap {
      float3 dir = normalize(texelDirection);
      float3 color = SampleCubemap(texel);
      for (int l=0; l<=2; ++l) {
      for (int m=-l; m<=l; ++m) {
      SHCoeff[l][m] += color * SHBasis(l,m,dir) * solidAngle;
      }
      }
      }

      实际工程中会使用重要性采样优化计算量。

    • 运行时重建

      在Shader中通过法线向量与预计算系数的点积快速重建光照:

      hlsl
      // URP中的SH重建代码(简化版)
      float3 SampleSH(float3 normalWS) {
      float4 vB = normalWS.xyzz * normalWS.yzzx;
      float3 x1 = float3(dot(unity_SHAr, normalWS),
      dot(unity_SHAg, normalWS),
      dot(unity_SHAb, normalWS));
      float3 x2 = float3(dot(unity_SHBr, vB),
      dot(unity_SHBg, vB),
      dot(unity_SHBb, vB));
      return x1 + x2 + unity_SHC.rgb;
      }

      此代码对应三阶SH重建公式:

      $L(n)=\sum_{l=0}{2}\sum_{m=−l}c_{l,m}Y_{l,m}(n)$

    该技术解决了动态物体无法实时计算全局光照的问题,通过球谐函数(SH)或光照探针存储预计算数据,显著降低实时渲染开销。

  • 探针混合‌:动态物体通过插值邻近探针数据实现平滑过渡,避免光照突变。

    光照探针数据生成

    • 探针烘焙

      每个光照探针位置会生成球谐系数,通过射线追踪计算周围几何体的间接光照。Unity使用伴随勒让德多项式作为基函数,存储7个half4变量(unity_SHAr至unity_SHC)。

    • 动态物体采样

      动态物体通过插值邻近探针的SH系数实现光照混合:

      hlsl
      // 探针混合伪代码
      float3 GetProbeIrradiance(float3 position) {
      Probe probes = FindNearbyProbes(position);
      float3 sh = lerp(probes[0].SH, probes[1].SH, weight);
      return SampleSH(sh, normalWS);
      }

      该方案解决了动态物体与环境光的一致性问题

  • 硬件优化‌:SH计算使用GPU并行,在Shader中通过SampleSH函数直接采样,避免实时积分。

技术对比优势

方案 内存占用 计算开销 适用场景
立方体贴图 6MB+ 静态环境反射
球谐光照(SH) 108字节 极低 动态物体漫反射
光照探针 可变 复杂动态场景

SH方案通过基函数投影实现高频信息剔除,特别适合Lambertian漫反射的低频特性。Unity选择该方案因其在移动端可实现0.5ms内的环境光重建,且支持动态更新.

具体实现示例

在URP Shader中,漫反射辐照通过以下HLSL代码实现:

hlsl
// 球谐采样
float3 irradiance = SampleSH(normalWS);
// 结合材质反照率
float3 diffuse = albedo * irradiance;

此过程将预计算的球谐系数与表面法线点乘,重建环境光照。例如,金属材质通过调整反照率c控制能量守恒,非金属材质则保留更多散射光。

镜面IBL的协同作用

镜面IBL(Specular IBL)通过分裂求和近似(Split Sum Approximation)处理高光反射,与漫反射辐照共同构成完整的PBR环境光照模型。预滤波环境贴图(粗糙度分级)和BRDF LUT分别处理光线散射与菲涅尔效应,公式为:

$L_s=\int_\Omega f_r(\omega_i,\omega_o)L_i(\omega_i)(n\cdot \omega_i)d\omega_i$

其中fr为BRDF函数。Unity选择此方案因其在移动端仅需两次纹理采样即可实现物理精确的高光反射,平衡性能与效果


【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,)

【光照】Unity[PBR]环境光中的[漫反射]的更多相关文章

  1. Unity 5.6中的混合光照(下)

    https://mp.weixin.qq.com/s/DNQFsWpZm-ybIlF3DTAk2A 在<Unity 5.6中的混合光照(上)>中,我们介绍了混合模式,以及Subtracti ...

  2. Unity 5.6中的混合光照(上)

    https://mp.weixin.qq.com/s/AbWM21sihHw5pFdMzENDPg 在Unity 5中,光照得到了很大的改进.现在,创建高度逼真的游戏已成为可能.但是,出于对性能的考虑 ...

  3. Unity项目开发过程中常见的问题,你遇到过吗?

    最近看到有朋友问一个unity游戏开发团队,需要掌握哪些知识之类的问题.事实上Unity引擎是一个很灵活的引擎,根据团队开发游戏类型的不同,对人员的要求也有差异,所以不能一概而论.但是,一些在Unit ...

  4. [转] Draw Call未被批处理?告诉你在Unity 5.6中如何查找原因 [复制链接]

    Unity在5.6之前的版本中并未提供很直接的方式来查找Draw Call未被批处理的原因,但Unity 5.6在Frame Debugger中新增了一项功能,帮助开发者查找相关信息.今天这篇文章就为 ...

  5. DDD~Unity在DDD中的使用

    回到目录 上一讲介绍了DDD中的领域层,并提到下次要讲Unity,所以这篇文章当然就要介绍它了,呵呵,Unity是Microsoft.Practices中的一部分,主要实现了依赖注入的功能,或者叫它控 ...

  6. Unity制作游戏中的场景

    Unity制作游戏中的场景 1.2.3  场景 在Unity中,场景(Scene)就是游戏开发者制作游戏时,所使用的游戏场景.它是一个三维空间,对应的三维坐标轴分别是X轴.Y轴和Z轴本文选自Unity ...

  7. Unity3D 将 Unity 嵌入WPF中的一些研究笔记

     一. 在 WPF 中使用 WebBrowser,直接打开 WebPlayer.html 以这种方式有一个问题是. 无法在 WebBrowser 的上面 放置其它的控件, 在运行时,都不会显示 . 以 ...

  8. 【Unity游戏开发】浅谈Unity游戏开发中的单元测试

    一.单元测试的定义与作用 单元测试定义:单元测试在传统软件开发中是非常重要的工具,它是指对软件中的最小可测试单元进行检查和验证,一般情况下就是对代码中的一个函数去进行验证,检查它的正确性.一个单元测试 ...

  9. Unity 处理预设中的中文

    Unity 处理预设中的中文 需求由来 项目接入越南版本 需要解决的文本问题 获取UI预设Label里面的中文(没被代码控制)提供给越南 Label里面的中文替换成越南文 解决流程 迭代获取Asset ...

  10. Unity 4.0 中的新动画系统——MecAnim

    分享一个文档资料,关于动画系统的,版本应该很老了,但是有借鉴意义的: Unity 4.0 已于 2012 年 11 月 15 日正式发布,Unity 每一次版本的提升,都给游戏开发者带来惊喜,这一次也 ...

随机推荐

  1. SciTech-Mathmatics-Probability+Statistics-IV-Population:Parameter<->Sample:Statistics : Confidence Interval(置信区间)

    SciTech-Mathmatics-Probability+Statistics-IV- Population:Parameter<->Sample:Statistics : CI(Co ...

  2. linux操作系统中rpm离线包的下载和安装--九五小庞

    前言 在Linux操作系统中当需要安装相关程序包时,如果有网络的情况下,可以直接通过yum源命令直接进行下载安装,比较简单方便.但是在没有互联网的情况下,需要下载对应的rpm包,进行离线安装. 1.下 ...

  3. Unity编辑器调用外部exe程序 和 windows文件夹

    直接来,1个脚本 using System.Collections; using System.Collections.Generic; using System.Diagnostics; using ...

  4. Java面向对象——5.多态

    目录 Java多态(Polymorphic) 多态的实现条件 构造的示例 多态的本质:动态绑定 动态绑定的示例 多态的工作原理 覆写Object方法 多态的限制与控制:final关键字 final的三 ...

  5. 简述 Java 中的线程同步机制,synchronized 关键字和 ReentrantLock 的区别是什么?

    语法层面 synchronized:是 Java 中的关键字,是一种内置的同步机制.它可以修饰方法或者代码块,使用起来比较简洁.例如: // 同步方法 public synchronized void ...

  6. [题解]SFMOI Round I A~C

    Portal:https://www.luogu.com.cn/contest/179008 \(\bf{100+50+50+25+5=\color{indianred}225}\)\(\bf{\ , ...

  7. axios 传递参数的方式(data 与 params 的区别)

    1.get请求 axios({ method: 'GET', url: '/xxx', params: param, }) 或者 axios({ method: 'GET', url: '/xxx?m ...

  8. 一步一步学习使用FireMonkey动画(1) 使用动画组件为窗体添加动态效果

    FireMonkey提供了一系列的动画控件,为基于FMX(FireMonkey的简称)的应用程序开发提供了较大的灵活性.在VCL上面创建动画,需要开发人员用一个TTimer组件,然后不断的移动目标物体 ...

  9. unordered_map的理解和应用

    1.介绍 unordered_map,它是一个关联容器,内部采用的是hash表结构,拥有快速检索的功能. 1.1.特性 关联性:通过key去检索value,而不是通过绝对地址(和顺序容器不同) 无序性 ...

  10. Net Core 3.1 处理JSON返回的时间格式

    在网上找了好多好多的帖子都是2.x的,代码放进去一直报错没法用,刚刚准备关机找到一个可以用的~特此记录一下. 直接把这一行放进去,这个时候DatetimeJsonConverter会报错,不要慌.接着 ...