目录
[1 前言](#1 前言)
[2 光照介绍](#2 光照介绍)
[2.1 直接光与间接光](#2.1 直接光与间接光)
[2.2 实时光照与烘焙光照](#2.2 实时光照与烘焙光照)
[2.3 全局光照](#2.3 全局光照)
[3 光源](#3 光源)
[3.1 Directional Light](#3.1 Directional Light)
[3.1.1 Color](#3.1.1 Color)
[3.1.2 Mode](#3.1.2 Mode)
[3.1.3 Intensity](#3.1.3 Intensity)
[3.1.4 Indirect Multiplier](#3.1.4 Indirect Multiplier)
[3.1.5 Shadow Type](#3.1.5 Shadow Type)
[3.1.6 Baked Shadow Angle](#3.1.6 Baked Shadow Angle)
[3.1.7 Realtime Shadows](#3.1.7 Realtime Shadows)
[3.1.7.1 Strength](#3.1.7.1 Strength)
[3.1.7.2 Resolution](#3.1.7.2 Resolution)
[3.1.7.3 Bias](#3.1.7.3 Bias)
[3.1.7.4 Normal Bias](#3.1.7.4 Normal Bias)
[3.1.7.5 Near Plane](#3.1.7.5 Near Plane)
[3.1.8 Cookie](#3.1.8 Cookie)
[3.1.9 Draw Halo](#3.1.9 Draw Halo)
[3.1.10 Flare](#3.1.10 Flare)
[3.1.11 Render Mode](#3.1.11 Render Mode)
[3.1.12 Culling Mask](#3.1.12 Culling Mask)
[3.2 Point Light](#3.2 Point Light)
[3.2.1 Range](#3.2.1 Range)
[3.2.2 Baked Shadow Radius](#3.2.2 Baked Shadow Radius)
[3.3 Spot Light](#3.3 Spot Light)
[3.3.1 Spot Angle](#3.3.1 Spot Angle)
[3.4 Area Light](#3.4 Area Light)
[3.5 注意点](#3.5 注意点)
[3.6 光照模式](#3.6 光照模式)
[3.6.1 Realtime](#3.6.1 Realtime)
[3.6.2 Baked](#3.6.2 Baked)
[3.6.3 Mixed](#3.6.3 Mixed)
[3.7 Cookies](#3.7 Cookies)
[3.7.1 启用和禁用Baked Cookies](#3.7.1 启用和禁用Baked Cookies)
[3.7.2 为内置渲染管线创建Cookie](#3.7.2 为内置渲染管线创建Cookie)
[3.8 发光材质](#3.8 发光材质)
[3.8.1 演示](#3.8.1 演示)
[3.9 环境光](#3.9 环境光)
[4 阴影](#4 阴影)
[4.1 阴影映射](#4.1 阴影映射)
[4.1.1 阴影映射是如何工作的](#4.1.1 阴影映射是如何工作的)
[4.1.2 阴影贴图分辨率](#4.1.2 阴影贴图分辨率)
[4.1.3 替换阴影贴图分辨率](#4.1.3 替换阴影贴图分辨率)
[4.2 阴影配置项](#4.2 阴影配置项)
[4.3 阴影距离](#4.3 阴影距离)
[4.3.1 设置阴影距离](#4.3.1 设置阴影距离)
[4.3.2 减少闪烁阴影](#4.3.2 减少闪烁阴影)
[4.3.2 阴影距离与阴影遮罩光照模式](#4.3.2 阴影距离与阴影遮罩光照模式)
[4.4 阴影层叠](#4.4 阴影层叠)
[4.4.1 透视混叠](#4.4.1 透视混叠)
[4.4.2 阴影层叠原理](#4.4.2 阴影层叠原理)
[4.4.3 使用阴影层叠](#4.4.3 使用阴影层叠)
[4.5 阴影问题解决方案](#4.5 阴影问题解决方案)
[4.5.1 阴影性能](#4.5.1 阴影性能)
[4.5.2 阴影暗斑](#4.5.2 阴影暗斑)
[4.5.3 光偏移设置](#4.5.3 光偏移设置)
[4.5.4 阴影平坠](#4.5.4 阴影平坠)
[4.5.5 阴影不显示](#4.5.5 阴影不显示)
[5 全局光照](#5 全局光照)
[5.1 让物体参与GI](#5.1 让物体参与GI)
[5.2 实时GI](#5.2 实时GI)
[5.2.1 演示](#5.2.1 演示)
[5.3 烘焙GI](#5.3 烘焙GI)
[5.3.1 Mixed](#5.3.1 Mixed)
[5.3.2 Mixed演示](#5.3.2 Mixed演示)
[5.3.3 Baked](#5.3.3 Baked)
[5.3.4 Baked演示](#5.3.4 Baked演示)
[5.4 Lighting窗口](#5.4 Lighting窗口)
[5.4.1 相关 API](#5.4.1 相关 API)
[5.4.2 内部包含的窗口](#5.4.2 内部包含的窗口)
[5.4.3 Scene](#5.4.3 Scene)
[5.4.3.1 Lighting Settings](#5.4.3.1 Lighting Settings)
[5.4.3.2 Realtime Lighting](#5.4.3.2 Realtime Lighting)
[5.4.3.3 Mixed Lighting](#5.4.3.3 Mixed Lighting)
[5.4.3.4 Lightmapping Settings](#5.4.3.4 Lightmapping Settings)
[5.4.3.5 Workflow Settings](#5.4.3.5 Workflow Settings)
[5.4.4 Environment](#5.4.4 Environment)
[5.4.4.1 Environment](#5.4.4.1 Environment)
[5.4.4.2 Other Settings](#5.4.4.2 Other Settings)
[5.4.5 Realtime Lightmaps](#5.4.5 Realtime Lightmaps)
[5.4.6 Baked Lightmaps](#5.4.6 Baked Lightmaps)
[5.4.7 Probe Volumes](#5.4.7 Probe Volumes)
[5.4.8 Control Area](#5.4.8 Control Area)
[6 光照设置资源](#6 光照设置资源)
[6.1 创建Asset文件](#6.1 创建Asset文件)
[6.2 将Asset设置给场景](#6.2 将Asset设置给场景)
[6.3 查看和编辑Asset的属性](#6.3 查看和编辑Asset的属性)
[6.4 默认LightingSettings数据](#6.4 默认LightingSettings数据)
[6.5 属性介绍](#6.5 属性介绍)
[6.6 Lighting Mode](#6.6 Lighting Mode)
[6.6.1 Baked Indirect](#6.6.1 Baked Indirect)
[6.6.1.1 渲染管线支持](#6.6.1.1 渲染管线支持)
[6.6.1.2 混合光行为](#6.6.1.2 混合光行为)
[6.6.1.3 阴影与运行时性能](#6.6.1.3 阴影与运行时性能)
[6.6.1.4 运行是改变光属性](#6.6.1.4 运行是改变光属性)
[6.6.2 Shadowmask](#6.6.2 Shadowmask)
[6.6.2.1 渲染管线支持](#6.6.2.1 渲染管线支持)
[6.6.2.2 Shadowmask质量设置](#6.6.2.2 Shadowmask质量设置)
[6.6.2.3 混合光行为](#6.6.2.3 混合光行为)
[6.6.2.4 阴影与运行时性能](#6.6.2.4 阴影与运行时性能)
[6.6.2.5 阴影遮罩实现详细信息](#6.6.2.5 阴影遮罩实现详细信息)
[6.6.3 Subtractive](#6.6.3 Subtractive)
[6.6.3.1 渲染管线支持](#6.6.3.1 渲染管线支持)
[6.6.3.3 更改阴影颜色](#6.6.3.3 更改阴影颜色)
[6.6.3.4 主方向光](#6.6.3.4 主方向光)
[7 Light Explorer窗口](#7 Light Explorer窗口)
[7.1 窗口介绍](#7.1 窗口介绍)
[7.2 窗口扩展](#7.2 窗口扩展)
[7.2.1 扩展方法](#7.2.1 扩展方法)
[7.2.2 有用的类和方法](#7.2.2 有用的类和方法)
[8 光照映射](#8 光照映射)
[8.1 Progressive Lightmapper](#8.1 Progressive Lightmapper)
[8.1.1 CPU、GPU Progressive Lightmapper](#8.1.1 CPU、GPU Progressive Lightmapper)
[8.1.2 渲染管线支持](#8.1.2 渲染管线支持)
[8.1.3 平台兼容性](#8.1.3 平台兼容性)
[8.1.4 设置Progressive Lightmapper](#8.1.4 设置Progressive Lightmapper)
[8.1.5 高级过滤设置](#8.1.5 高级过滤设置)
[8.1.6 统计信息](#8.1.6 统计信息)
[8.1.7 ETA](#8.1.7 ETA)
[8.2 Progressive GPU Lightmapper](#8.2 Progressive GPU Lightmapper)
[8.2.1 硬件和软件要求](#8.2.1 硬件和软件要求)
[8.2.2 性能](#8.2.2 性能)
[8.2.3 防止因光照贴图器tiling引起的烘烤速度减慢](#8.2.3 防止因光照贴图器tiling引起的烘烤速度减慢)
[8.2.4 特定平台限制](#8.2.4 特定平台限制)
[8.2.5 如何优化烘焙速度](#8.2.5 如何优化烘焙速度)
[8.2.6 配置GPU的选择](#8.2.6 配置GPU的选择)
[8.3 光照映射:入门](#8.3 光照映射:入门)
[8.4 预览光照映射](#8.4 预览光照映射)
[8.5 Lightmap Parameters Asset](#8.5 Lightmap Parameters Asset)
[8.5.1 创建](#8.5.1 创建)
[8.5.2 属性](#8.5.2 属性)
[8.5.2.1 Realtime Global Illumination](#8.5.2.1 Realtime Global Illumination)
[8.5.2.2 Baked Global Illimination](#8.5.2.2 Baked Global Illimination)
[8.5.2.3 Baked Tags: Details](#8.5.2.3 Baked Tags: Details)
[8.5.3 Baked AO](#8.5.3 Baked AO)
[8.5.4 分配Lightmap Parameters Asset](#8.5.4 分配Lightmap Parameters Asset)
[8.5.4.1 分配给场景](#8.5.4.1 分配给场景)
[8.5.4.2 分配给游戏对象](#8.5.4.2 分配给游戏对象)
[8.6 光照贴图模式](#8.6 光照贴图模式)
[8.6.1 模式](#8.6.1 模式)
[8.6.2 性能问题](#8.6.2 性能问题)
[8.6.3 设置光照贴图的模式](#8.6.3 设置光照贴图的模式)
[8.6.4 附加场景时的注意点](#8.6.4 附加场景时的注意点)
[8.7 环境光遮挡](#8.7 环境光遮挡)
[8.7.1 烘焙环境光遮挡](#8.7.1 烘焙环境光遮挡)
[8.7.2 实时环境光遮挡](#8.7.2 实时环境光遮挡)
[8.7.3 其他资源](#8.7.3 其他资源)
[8.8 光照贴图:技术信息](#8.8 光照贴图:技术信息)
[8.8.1 编码方案](#8.8.1 编码方案)
[8.8.2 HDR光照贴图支持](#8.8.2 HDR光照贴图支持)
[8.8.3 高质量(BC6H)光照贴图的优点](#8.8.3 高质量(BC6H)光照贴图的优点)
[8.8.4 预计算实时全局光照 (GI)](#8.8.4 预计算实时全局光照 (GI))
[8.9 光照映射与着色器](#8.9 光照映射与着色器)
[8.9.1 The Meta Pass](#8.9.1 The Meta Pass)
[8.9.2 带有Meta Pass的着色器实例](#8.9.2 带有Meta Pass的着色器实例)
[8.9.3 Meta Pass 技术信息](#8.9.3 Meta Pass 技术信息)
[8.9.4 自定义RGB透明度](#8.9.4 自定义RGB透明度)
[8.10 光照贴图UVs](#8.10 光照贴图UVs)
[8.10.1 介绍](#8.10.1 介绍)
[8.10.1.1 Baked lightmap UVs](#8.10.1.1 Baked lightmap UVs)
[8.10.1.2 Real-time lightmap UVs](#8.10.1.2 Real-time lightmap UVs)
[8.10.1.3 Unity如何计算real-time lightmap UVs](#8.10.1.3 Unity如何计算real-time lightmap UVs)
[8.10.2 生成光照贴图 UV](#8.10.2 生成光照贴图 UV)
[8.10.2.1 如何提供自己的光照贴图UVs](#8.10.2.1 如何提供自己的光照贴图UVs)
[8.10.2.2 如何自动生成光照贴图UVs](#8.10.2.2 如何自动生成光照贴图UVs)
[8.10.2.3 自动生成光照贴图UVs问题解决](#8.10.2.3 自动生成光照贴图UVs问题解决)
[8.10.3 可视化光照贴图UVs](#8.10.3 可视化光照贴图UVs)
[8.10.4 解决光照贴图UV重叠](#8.10.4 解决光照贴图UV重叠)
[8.10.4.1 识别](#8.10.4.1 识别)
[8.10.4.2 解决方案](#8.10.4.2 解决方案)
[8.11 光照贴图接缝缝合](#8.11 光照贴图接缝缝合)
[8.11.1 接缝缝合的局限性](#8.11.1 接缝缝合的局限性)
[8.11.2 使用接缝缝合](#8.11.2 使用接缝缝合)
[8.12 自定义衰减](#8.12 自定义衰减)
[9 Enlighten实时全局光照](#9 Enlighten实时全局光照)
[9.1 渲染管线支持](#9.1 渲染管线支持)
[9.2 何时使用](#9.2 何时使用)
[9.3 使用](#9.3 使用)
[9.4 如何工作的](#9.4 如何工作的)
[9.5 光照探针与实时GI](#9.5 光照探针与实时GI)
[9.6 阴影与实时GI](#9.6 阴影与实时GI)
[9.7 性能注意事项](#9.7 性能注意事项)
[9.8 优化实时GI](#9.8 优化实时GI)
[9.9 LOD和实时GI](#9.9 LOD和实时GI)
[10 光照探针](#10 光照探针)
[10.1 光照探针技术信息](#10.1 光照探针技术信息)
[10.2 Light Probe Group组件](#10.2 Light Probe Group组件)
[10.2.1 创建](#10.2.1 创建)
[10.2.2 组件属性](#10.2.2 组件属性)
[10.2.3 案例](#10.2.3 案例)
[10.2.4 Ringing现象](#10.2.4 Ringing现象)
[10.2.5 放置位置](#10.2.5 放置位置)
[10.2.6 体积问题](#10.2.6 体积问题)
[10.2.7 移动光源与光照探针](#10.2.7 移动光源与光照探针)
[10.2.8 放置位置错误情况](#10.2.8 放置位置错误情况)
[10.3 脚本创建光照探针思路](#10.3 脚本创建光照探针思路)
[10.4 MeshRenderer](#10.4 MeshRenderer)
[10.5 场景加载](#10.5 场景加载)
[10.6 运行时移动光照探针](#10.6 运行时移动光照探针)
[10.7 Light Probe Proxy Volume组件](#10.7 Light Probe Proxy Volume组件)
[10.7.1 组件使用前提](#10.7.1 组件使用前提)
[10.7.2 组件属性](#10.7.2 组件属性)
[10.7.3 案例](#10.7.3 案例)
[10.7.4 粒子系统样本着色器代码示例](#10.7.4 粒子系统样本着色器代码示例)
[10.7.5 硬件需求](#10.7.5 硬件需求)
[11 反射探针](#11 反射探针)
[11.1 背景](#11.1 背景)
[11.2 工作原理](#11.2 工作原理)
[11.3 反射探针类型](#11.3 反射探针类型)
[11.3.1 Baked反射探针](#11.3.1 Baked反射探针)
[11.3.1.1 特点](#11.3.1.1 特点)
[11.3.1.2 使用演示](#11.3.1.2 使用演示)
[11.3.2 Custom反射探针](#11.3.2 Custom反射探针)
[11.3.2.1 特点](#11.3.2.1 特点)
[11.3.3 Realtime反射探针](#11.3.3 Realtime反射探针)
[11.3.3.1 特点](#11.3.3.1 特点)
[11.3.3.2 使用演示](#11.3.3.2 使用演示)
[11.4 反射探针的使用](#11.4 反射探针的使用)
[11.4.1 默认反射探针](#11.4.1 默认反射探针)
[11.4.2 探针位置](#11.4.2 探针位置)
[11.4.3 重叠的作用范围](#11.4.3 重叠的作用范围)
[11.4.4 混合](#11.4.4 混合)
[11.4.4.1 Mesh Renderer(混合控制)](#11.4.4.1 Mesh Renderer(混合控制))
[11.4.4.2 混合权值计算](#11.4.4.2 混合权值计算)
[11.5 高级反射探针特性](#11.5 高级反射探针特性)
[11.5.1 互反射](#11.5.1 互反射)
[11.5.2 盒子投影](#11.5.2 盒子投影)
[11.6 反射探针性能](#11.6 反射探针性能)
[11.6.1 通用优化](#11.6.1 通用优化)
[11.6.1.1 Resolution](#11.6.1.1 Resolution)
[11.6.1.2 Culling Mask](#11.6.1.2 Culling Mask)
[11.6.1.3 Texture compression](#11.6.1.3 Texture compression)
[11.6.2 实时反射探针优化](#11.6.2 实时反射探针优化)
[11.6.2.1 Refresh Mode](#11.6.2.1 Refresh Mode)
[11.6.2.2 Time Slicing](#11.6.2.2 Time Slicing)
[11.7 反射探针组件](#11.7 反射探针组件)
[11.7.1 概念](#11.7.1 概念)
[11.7.2 属性与渲染管线](#11.7.2 属性与渲染管线)
[11.7.3 属性](#11.7.3 属性)
[11.7.3.1 Type](#11.7.3.1 Type)
[11.7.3.2 Runtime settings](#11.7.3.2 Runtime settings)
[11.7.3.3 Cubemap capture settings](#11.7.3.3 Cubemap capture settings)
[11.7.4 细节](#11.7.4 细节)
[12 预计算的光照数据](#12 预计算的光照数据)
[12.1 生成光照数据](#12.1 生成光照数据)
[12.1.1 生成数据](#12.1.1 生成数据)
[12.1.2 构建之前](#12.1.2 构建之前)
[12.2 光照数据Asset文件](#12.2 光照数据Asset文件)
[12.2.1 默认Asset文件](#12.2.1 默认Asset文件)
[12.3 全局光照缓存](#12.3 全局光照缓存)
[12.3.1 清理GI缓存](#12.3.1 清理GI缓存)
[13 调试光照的绘制模式](#13 调试光照的绘制模式)
[13.1 Lighting](#13.1 Lighting)
[13.1.1 Contributors / Receivers](#13.1.1 Contributors / Receivers)
[13.1.2 Shadow Cascades](#13.1.2 Shadow Cascades)
[13.2 Global Illumination](#13.2 Global Illumination)
[13.2.1 Indirect (Realtime Global Illumination only)](#13.2.1 Indirect (Realtime Global Illumination only))
[13.2.2 Directionality](#13.2.2 Directionality)
[13.2.3 Albedo](#13.2.3 Albedo)
[13.2.4 Emissive](#13.2.4 Emissive)
[13.2.5 UV Charts](#13.2.5 UV Charts)
[13.2.6 Systems (Realtime Global Illumination only)](#13.2.6 Systems (Realtime Global Illumination only))
[13.2.7 Clustering (Realtime Global Illumination only)](#13.2.7 Clustering (Realtime Global Illumination only))
[13.2.8 Lit Clustering (Realtime Global Illumination only)](#13.2.8 Lit Clustering (Realtime Global Illumination only))
[13.2.9 Texel Validity (Baked Global Illumination only)](#13.2.9 Texel Validity (Baked Global Illumination only))
[13.2.10 UV Overlap (Baked Global Illumination only)](#13.2.10 UV Overlap (Baked Global Illumination only))
[13.2.11 Lightmap indices (Baked Global Illumination only)](#13.2.11 Lightmap indices (Baked Global Illumination only))
[13.2.12 Light Overlap (Baked Global Illumination only)](#13.2.12 Light Overlap (Baked Global Illumination only))
[13.2.13 Baked Lightmap (Baked Global Illumination only)](#13.2.13 Baked Lightmap (Baked Global Illumination only))
[13.2.14 Shadowmask (Baked Global Illumination only)](#13.2.14 Shadowmask (Baked Global Illumination only))
[13.3 光照可视化悬浮窗口参考](#13.3 光照可视化悬浮窗口参考)
[13.4 更多内容](#13.4 更多内容)
[14 后记](#14 后记)
1 前言
关于Unity光照系统的一个笔记,主要是对官方文档内容的学习,总结下就是"文档翻译+自己的注释"。Unity中文和英文我都看,基本是结合着搞的,有些中文官方翻译甚至都有问题,一点都不上心。毕竟是个人笔记,也没法保证内容100%的正确性,不过基本没问题,遇到不懂的地方可以结合官方文档看。
虽然官方文档写得很烂,但不多不说里面的东西还是实在的。很多内容网上的教程是不会提的,但这些内容在文档中都会有提及,看了之后就会有原来如此的感觉。本身光照系统我是没打算看文档的,但教程内容缺乏,只能在文档中找内容看,发现了文档里包含了很多东西就转而直接看文档了。
看官方文档时,个人觉得完整的看完还是有必要的。比如我在看文档的某一块时,常常有看不懂的时候,不知道这里说的是什么,理解上有歧义,没法确定,但随着继续看下去,可能在其他部分就能看到相关联的内容,进而解决了之前遗留的疑惑。有一种单个知识点分散到整个文档的感觉,这也说明了官方文档的内容实际并不是严格按照知识点划分的,很多时候一个知识点需要从多个部分来了解,最终汇总理解。
另外,对于文中遇到的一些不懂的名词、给的链接,可以现在文中搜索下看看能不能搜到相关解释,前面也说了知识点是分散的,活用Ctrl+F。当然也可以用来在全文中查找相关内容的多个解释,比如文中介绍了一个属性,但描述简单令人难懂,这时候就可以全文搜索此属性名称,也许就可以在另一个小节中找到对其的详细解释了。
PS:
- 文档版本:Unity 6
- texel概念:纹理数组中的单个值,常常称为纹理单元,也叫纹素(纹理像素,texel)。
2 光照介绍
Unity中的照明工作原理近似于光在现实世界中的行为。Unity使用详细的光线工作模型,来获得逼真的光线效果。厚实使用简化的模型来获得更具风格化的效果。
2.1 直接光与间接光
直接光是发射出来的光,照射到物体表面一次,然后直接反射到传感器(例如,眼睛的视网膜或照相机)。间接光是指所有其他最终被反射到传感器中的光,包括多次照射物体表面反射的光和天空光。如图:

Unity可以计算直接光照,间接光照。具体光照技术的使用,取决于我们的项目配置。
2.2 实时光照与烘焙光照
实时光照是Unity在运行时实时计算的光照。烘焙光照是Unity提前执行光照计算,并将结果存储为光照数据,然后在运行时使用。在Unity中,我们可以只使用其中一种方式,或混合使用两种方式。
2.3 全局光照
全局光照(Global Illumination)是一组模拟直接光照、间接光照的基数,来提供逼真的光照效果。Unity有两个全局光照系统,包含了直接光照与间接光照。
- Baked Global Illumination系统由光照贴图(Lightmap)、光照探针(Light Probe)、反射探针(Reflection Probe)组成。我们可以使用Progressive Lightmapper(CPU或GPU)来执行烘焙操作。
- Real-time Global Illumination系统是Enlighten Realtime Global Illumination。
3 光源
这里介绍的光源都是在Unity内置渲染管线下的光源。右键创建灯光,和创建Cube类似,就不细说了。Light组件:

通过第一个属性Type,可以选择四种类型光源:
- Directional(方向光)
- Point(点光)
- Spot(聚光灯)
- Area(区域光)
后面将分别介绍。在介绍时,前面介绍过的属性后面便不再介绍。
3.1 Directional Light
方向光。方向光在许多方面的行为就像太阳一样,可以被认为是存在于无限远处的遥远光源。方向光没有任何可识别的光源位置,因此光照对象可以放置在场景中的任何地方。场景中的所有物体都可以被照亮,好像光线总是来自同一个方向。光与目标物体的距离没有定义,所以光不会因距离而减弱。
默认情况下,每个新的Unity场景都包含一个方向光。我们可以删除此光源,创建一个新的光源。

3.1.1 Color
调整光源颜色。
3.1.2 Mode
光照模式。有三种模式可选:
- Realtime(实时)
- Baked(烘焙)
- Mixed(混合)
3.1.3 Intensity
光照强度。
3.1.4 Indirect Multiplier
间接光照强度。若此值低于1,则每次光照反弹的光线变得越暗;若高于1,则每次反弹的光线就越亮。
3.1.5 Shadow Type
阴影类型。有三种,分别为:
- No Shadows(无阴影):即没有阴影,可以节省性能。
- Hard Shadows(硬阴影):硬阴影边缘存在锐利的形状,与软阴影相比其并不真实,但它只需要较少的处理,节省一些性能。
- Soft Shadows(软阴影):软阴影较为柔和、真实,但相对的也比较耗性能。
3.1.6 Baked Shadow Angle
烘焙阴影角?如果Model设置为Baked或Mixed,类型设置为定向,Shadow Type设置为Soft Shadows时,此属性可用。此属性设置可以在阴影边缘添加一些人工软化,并使其看起来更自然。
3.1.7 Realtime Shadows
在Model设置为Realtime或Mixed,Shadow Type设置为Hard Shadows或Soft Shadows时,此属性组可用。可使用这些属性来控制实时阴影渲染设置。
3.1.7.1 Strength
控制光照投射的阴影的暗度,用0到1之间的值表示。默认设置为1,最暗。
3.1.7.2 Resolution
控制阴影贴图的渲染分辨率。更高的分辨率增加了阴影的保真度,但需要更多的GPU时间和内存使用。
3.1.7.3 Bias
控制阴影偏移位置,值范围0-2,用于调整阴影位置。默认值0.05。
3.1.7.4 Normal Bias
控制阴影投射表面沿表面法线收缩的距离,定义为0到3之间的值,用于调整阴影位置。默认值0.4。
3.1.7.5 Near Plane
在渲染阴影时,控制阴影与物体表面距离的参数,定义为0.1到10之间的值。这个值被限制在0.1个单位或光的范围属性的1%,以较低者为准。默认设置为0.2。
3.1.8 Cookie
指定一个纹理蒙版,通过它投射阴影(例如,为光创建轮廓或图案照明)。即投射图案阴影。同时通过其下方的Size设置投影图案的大小。
3.1.9 Draw Halo
绘制光环。若有Range属性时(点光、聚光灯才有),Range可以控制光环的大小。Halo是一个组件。
3.1.10 Flare
可提供一个光晕(Flare)使用。Flare是一种asset资源。
3.1.11 Render Mode
渲染方式。可以设置所选光源的渲染优先级,这会影响光照保真度和性能。可选方式:
- Auto:在运行时确定渲染方法,具体取决于附近光源的亮度和当前项目设置中的Quality是如何设置的。
- Important:光线总是以每像素的质量渲染(像素光)。只对最明显的视觉效果使用重要模式(例如,玩家汽车的前灯)。效果好,吃性能。
- No Important:带你观点光源以快速、顶点/对象模式进行渲染(顶点光)。
3.1.12 Culling Mask
可设置哪些层下的物体是否会被此光源光照影响。选中的层是会受光照影响的。
3.2 Point Light
点光。由一点向四周发射光线,比如"火把"、"灯泡"。光照强度随距离光源的远近而减小,在一定范围内达到零。光强与到光源距离的平方成反比。这被称为"平方反比定律",与光在现实世界中的行为类似。

3.2.1 Range
可设置点光源的光照范围,或者理解为光传播的距离。(此属性仅点光和聚光灯才有)
3.2.2 Baked Shadow Radius
此属性只有在Type为Point、Spot,Mode为Baked、Mixed,Shadow Type为Soft Shadows时,才可用。此属性将在阴影边缘添加一些人工软化,使其看起来更自然。
3.3 Spot Light
聚光灯。字面意思,从一个点往某一方向投射光。与点光类似,聚光灯也有自己特定的范围,是一个锥形区域,在此范围外光线将消失。光线在聚光灯锥的边缘也会减弱,角度的扩大可以增加圆锥体的宽度,并随之增加了这种褪色的大小,称为"半影(penumbra)"。

3.3.1 Spot Angle
调整聚光灯锥底的角度(以度为单位)。
3.4 Area Light
区域光。在场景中由矩形或圆形定义的光,在其表面均匀地向所有方向发射光,但只从矩形或圆形的一侧发射光。区域光提供的照明强度以与光源距离的平方成反比的速率衰减。不能用于实时运行,只能用于烘焙全局光照,需要使用"Baked Global Illumination",全局光照后面会讲。
因为一个区域光同时从几个不同的方向照亮一个物体,所以阴影比其他类型的光更柔和和微妙。我们可以用它来创建一个逼真的街灯或一排靠近玩家的灯。一个小的区域光可以模拟较小的光源(如室内照明),但效果比点光更逼真。

3.5 注意点
- 如果我们创建一个带有Alpha通道的纹理,并设置到光源组件的Cookie属性上,那么Cookie就会从光源投射出来。Cookie的Alpha Mask可以调节光线的亮度,在光照表明产生明暗斑点,这可以为场景增加复杂性或氛围。
- VertexLit着色器不能显示cookie或阴影。
- 请注意,当使用正向渲染时,带有cookie的方向光的阴影是禁用的。在这种情况下,可以编写自定义着色器来启用阴影。更多细节见文档writing surface shaders。
小提示:
- 聚光灯可以非常有效地创造从窗户进来的光的效果。
- 低强度点光可以很好地为场景提供深度。
- 为了获得最佳性能,可以考虑使用VertexLit着色器。这个着色器只做每个顶点的光照,在低端卡上提供更高的吞吐量。不过一般是不建议使用此着色器,老着色器了。
3.6 光照模式
光照模式分为三种:Realtime、Baked、Mixed。
3.6.1 Realtime
此模式为实时光。Unity在运行时执行实时灯光的照明计算,每帧一次。我们可以在运行时更改实时灯光的属性,以创建诸如灯泡闪烁或火炬通过黑暗房间的效果。实时灯光通常用于在角色或可移动的几何体上照明和投射阴影。
实时光行为:
- 实时灯光投射阴影到阴影距离(Shadow Distance)。
- 默认情况下,实时灯光只向场景提供实时直接光照。如果你使用内置的渲染管道,并且在你的项目中启用了Realtime Global Illumination(全局光照部分的内容),实时光照也会为场景提供实时的间接光照。
实时光限制:
- 实时光耗费性能,尤其在复杂场景。
- 因为实时灯光在默认情况下只为场景提供直接光照,所以阴影看起来完全是黑色的,没有任何间接光照效果,例如颜色反弹。这可能会导致场景中的灯光不真实。
3.6.2 Baked
此模式为烘焙光。Unity在编辑器中执行烘焙灯光的计算,并将结果作为光照数据保存到磁盘上,这个过程叫做烘焙。在运行时,Unity加载烘焙的光照数据,并使用它来照亮场景。因为复杂的计算是提前完成的,所以烘焙光在运行时减少了阴影成本,并减少了阴影的渲染成本。烘焙光照对于运行时不会改变的东西很有用,比如风景。
烘焙光行为:
- Unity将直接光和间接光烘焙到光照贴图(lightmap)中。
- Unity将直接光和间接光烘焙到光照探针(Light Probe)中。
烘焙光限制:
- 在运行时,无法更改烘焙光的属性。
- 烘焙光不会产生镜面照明(specular lighting)。
- 动态物体无法使用烘焙光。
注意,如果我们禁用Baked Global Illumination,再强制执行烘焙行为,那么些设置为Baked、Mixed模式的灯光将像将它们的模式设置为实时一样。当这种情况发生时,Unity会在Light组件上显示一个警告。
3.6.3 Mixed
此模式为混合光。混合灯光结合了实时光和烘焙光。拥有实时的直接光、烘焙的间接光。可以实现动态阴影与来自同一光源的烘焙光照的结合。
混合光行为:
- 场景中所有混合光的行为取决于Lighting window中的Lighting Mode设置。不同选项的设置具有非常不同的性能特征,以及不同的视觉保真度。
- 可以在运行时改变混合光,这将会更新实时光照的部分,所以要注意可能产生的异常视觉效果出现。
混合光限制:
- 混合光的性能成本根据Lighting Mode的不同而有很大的区别。其涉及一部分的实时光计算,一部分的烘焙光计算,一个占运算时间,一个占内存空间,所以使用时要权衡性能。
3.7 Cookies
Cookie是一个蒙版,我们把它放在一个光源上,可以通过改变光的外观和强度来创建一个具有特定形状或颜色的阴影。Cookie是一种模拟复杂灯光效果的有效方法,对运行时性能的影响最小或没有影响。可以用Cookie模拟的效果包括焦散、柔和阴影和光线形状。
Cookie在Light组件的Cookie属性上设置。
Cookie可能支持不同的特性,这取决于我们使用的渲染管线。
使用Baked Light Cookies而实现的假焦散效果:

3.7.1 启用和禁用Baked Cookies
对于在Unity 2020.1或更高版本中创建的项目,默认情况下,Progressive Lightmapper中的Baked灯光和Mixed灯光会启用Baked Cookies。对于在2020.1之前版本的Unity中创建的项目,默认情况下,Progressive Lightmapper中的Baked灯光和Mixed灯光的Baked Cookies是禁用的。这是为了提供向后兼容性。
我们可以在编辑器设置窗口中设置在Progressive Lightmapper中,Cookies是否被用于Baked、Mixed灯光。如图:

3.7.2 为内置渲染管线创建Cookie
使用内置渲染管道创建Cookie最方便的方法是创建一个灰度纹理,将该纹理导入Unity,然后让Unity将纹理的亮度转换为alpha。注意,在内置渲染管道中,Cookie只使用来自alpha通道的数据,这意味着我们可以为Cookie定义形状,但不能定义颜色。
首先要有张图像:

然后就将其拖拽到项目当中,设置其类型,如图:

创建一个场景,去掉天空盒(让场景暗一点),创建Spot Light,将图片拖到Cookie属性上,如图:

PS:Cookie的像素不需要完全透明或不透明,但也可以包含介于两者之间的任何值。我们可以使用中间值来模拟光线路径中的灰尘或污垢,或模拟腐蚀性效应,例如由汽车前灯的脊线产生的效应。
3.8 发光材质
发光材质(Emissive materials)可以让物体表面发光,并且相关属性可以在运行时修改,即可实时状态下使用发光材质。发射"是标准着色器的一个属性,它允许场景中的静态物体发光。默认情况下,"发射"的值被设置为零,这意味着使用标准着色器分配材质的物体不会发出光。
发光材质没有范围值,但发射的光将再次以二次速率衰减。
只有在Inspector面板中设置为Static(Contribute GI)才能接收到发射的光线。同样,也只有静态物体才能使用发光材质对场景造成光照影响,若是非静态,则自身发光但不会对场景造成影响。对于静态物体,若也想自身发光但不对场景造成影响,那么我们可以在材质的属性设置面板中设置来实现此效果,只需要将Global Illumination设置为None即可。发射材料只直接影响场景中的静态几何对象,如果需要动态或非静态几何对象来收到光照影响,则需要使用光照探针。
像这样的自发光材料是创造霓虹灯或其他可见光源效果的有效方法。
3.8.1 演示
首先创建一个材质,然后将其放到一个物体上,注意材质的属性,如图:

勾选Emission,材质即可变为发光材质。Color处可以修改光的颜色、强度。Global Illumination修改全局光照类型,有Realtime、Baked、None。None前面说过了,就是自身发光但不影响周围环境;Realtime需要配合"实时全局光照"使用,Baked需要配合"烘焙全局光照"使用(全局光照(Global Illumination)部分的内容,可以之后再单独了解)。这里我们以Realtime来演示:

3.9 环境光
环境光(Ambient light),也被称为漫射环境光,是存在于场景周围的光,并不来自任何特定的源对象。它可以对场景的整体外观和亮度做出重要贡献。环境光在很多情况下都是很有用的,这取决于我们项目的艺术风格。比如卡通风格,可能就需要明亮的环境光,甚至照明效果也是手绘到纹理中的。另外,也可以通过环境光来调整整个场景的亮度,而不需要调整其他灯光。
环境光可以在Lighting面板中设置。另外,环境光也是会被"实时全局光照"与"烘焙全局光照"系统所影响的。
4 阴影
4.1 阴影映射
Unity使用一种称为阴影映射(shadow mapping)的技术来渲染实时阴影。
4.1.1 阴影映射是如何工作的
阴影映射使用称为阴影贴图(shadow maps)的纹理。阴影贴图类似于深度纹理。光源生成阴影贴图的方式与相机生成深度纹理的方式类似。可以想象一个相机与光源在同一位置,那么相机看不到的场景区域就是光线无法到达的场景区域,因此,他们处于阴影之中。
Unity在阴影贴图中填充了光线在达到物体表明之前所走过的距离信息,然后对阴影地图进行采样,以计算光线击中的GameObjects的实时阴影。
4.1.2 阴影贴图分辨率
首先,确定光可以照亮的屏幕视图的面积。对于方向光,可以照亮整个屏幕。对于聚光灯和点光,区域是光的范围的形状在屏幕上的投影(锥形、圆形)。投影形状在屏幕上具有以像素为单位的宽度和高度,然后取这两个值中较大的那个,这个值被称为光的像素尺寸。
然后,确定阴影质量的相乘系数。这个数值在Unity的Quality窗口中的Shadow Resolution属性这里设置(Project Settings→Quality→Shadows→Shadow Resolution)。可设置选项如下:
- Very High: 1.0
- High: 0.5
- Medium: 0.25
- Low: 0.125
最后,执行计算,并将结果裁剪到最大分辨率范围内。计算:
| 光照类型 | 计算公式 | 最大分辨率(像素单位) |
| 方向光 | NextPowerOfTwo (pixel size * shadow quality multiplier * 3.8) | 当阴影分辨率是非常高的质量或GPU有512MB或更多的RAM,则分辨率设置为4096×4096,否则为2048×2048。 |
| 聚光灯 | NextPowerOfTwo (pixel size * shadow quality multiplier * 2.0) | 如果GPU的内存大于等于512MB,则为2048 * 2048,否则为1024 * 1024 。 |
点光 | NextPowerOfTwo (pixel size * shadow quality multiplier * 1.0) | 如果GPU的内存大于等于512MB,则为1024 * 1024,否则为512 * 512。 |
---|
点光相比其他类型在尺寸上限制得更小,因为其使用Cubemap来绘制阴影。这意味着有相同分辨率的Cubemap的6个面会同时存储在显存中,另外,其渲染成本也是非常高的,因为潜在的阴影可能需要渲染到Cubemap的6个面中。
4.1.3 替换阴影贴图分辨率
在内置渲染管道中,我们可以通过将Light.shadowCustomResolution属性设置为一个大于零的值来设置灯光阴影贴图的分辨率。当这个值大于0时,Unity对所有的光源类型执行如下计算:NextPowerOfTwo (shadowCustomResolution)。其会根据Light类型与硬件情况计算,然后裁剪到最大分辨率范围内。
PS:我记得在灯光Inspector面板里也可以设置阴影质量相乘系数,可以选择使用质量面板的设置,也可以自己选择低高四个档位。
4.2 阴影配置项
在Light组件中可以设置灯光模式为Realtime、Baked、Mixed,对应的引用也会采用相对的模式。什么样的光产生什么样的阴影,实时光产生实时阴影,烘焙光产生烘焙阴影。具体会在全局光照里有讲到。
Mesh Renderer组件中有Cast Shadows和Receive Shadows属性,可分别设置物体本身是否可以投射阴影(有影子),以及是否接收阴影(身上可被投射别的物体的阴影)。
Cast Shadows的选项有:Off、On、Two Sided、Shadows Only。Off是关闭阴影投射;On是打开;Two Sided允许阴影投射到表面的任何一侧,因此为了投射阴影,背面剔除此时将被忽略;Shadows Only会使物体不可见,但阴影依旧存在。
4.3 阴影距离
阴影距离(Shadow Distance)用于确定从相机到Unity渲染实时阴影的最远距离,超过此距离就不渲染了。游戏对象离摄像机越远,其阴影越不明显,这是因为阴影在屏幕上显得比较小,而且远处的游戏对象通常不太会被关注。我们可以利用这个特点来降低渲染对性能的消耗,只需要禁用远距离游戏对象的实时阴影即可。另外,场景通常没有远处的阴影会看起来更好。
如果当前相机的近平面(Camera Far Plane)比阴影距离更近一些,则Unity会使用近平面距离,而非阴影距离。此时只有在近平面距离内的阴影才能被渲染。
超出阴影距离而没有被渲染的阴影,其缺失会比较显眼,我们可以使用相关视觉效果来遮掩它们,比如雾。
4.3.1 设置阴影距离
在使用Unity内置渲染管线的情况下,我们可以在项目的质量设置中设置阴影距离。如图:

在通用渲染管线( URP)中,在通用渲染管线的Asset中来设置阴影距离。
在高清渲染管线(HDRP)中,需要为每个Volume设置阴影距离。
4.3.2 减少闪烁阴影
如果阴影距离相机较远,则它们可能会出现闪烁的情况。更多信息参考 Understanding the View Frustum。
如果阴影比世界空间原点离相机更近,则启用相机相对剔除。Unity使用相机作为阴影计算的相对位置,而不是世界空间原点,这减少了闪烁。
要启用相机相对剔除,在下图中位置设置:

4.3.2 阴影距离与阴影遮罩光照模式
若在启用Baked Global Illimination后,选择了阴影遮罩(Shadowmask Lighting)模式,Unity可以使用光照探针或一个阴影遮罩纹理来渲染阴影距离以外的混合(Mixed)光阴影。我们可以配置Unity如何在阴影距离之外渲染阴影。
4.4 阴影层叠
阴影层叠(Shadow Cascades)有助于解决透视混叠(perspective aliasing)问题:当方向光的实时阴影靠近相机时,它们会出现像素化。阴影层叠只适用于方向光。
4.4.1 透视混叠
一个方向光通常模拟阳光,一个单一的方向光可以照亮整个场景。这意味着它的阴影贴图覆盖了场景的很大一部分,这可能导致一个叫做透视混叠的问题。透视混叠意味着靠近相机的阴影贴图像素相比于那些远离相机的看起来更大、更厚。

如图,远处(A)的阴影具有适当的分辨率,而靠近相机(B)的阴影显示透视混叠。
由于阴影贴图的不同区域被相机视角不成比例地缩放,因此会出现透视混叠。光线的阴影贴图只需要覆盖场景中相机可见的部分,这是由相机的视锥体(view frustum)定义的。比如,方向光直接从上方照下,产生一个阴影,如下图所示,我们就可以看到视椎体和阴影贴图之间的关系。

在这个简化的例子中,视椎体的远端被20个像素的阴影贴图覆盖,而近端仅被4个像素覆盖。然而,两端在屏幕上显示的尺寸相同(可以自己在场景里对着地面的线框试下)。结果是,对于靠近相机的阴影区域,其贴图的分辨率实际上要低得多。
4.4.2 阴影层叠原理
当我们使用Soft Shadows,并使用一个高分辨率的阴影贴图时,透视混叠实际是不明显的。但是这种处理方式在渲染时将会占用更多的内存和带宽。
当使用阴影层叠时,Unity将会根据距离相机的距离将视椎体划分为两个区域。在相机近端区域,使用一个单独的尺寸被缩放变小的阴影贴图(尺寸缩小,但分辨率不变)。这种阴影贴图尺寸的阶段性缩减,被称为级联阴影贴图(cascaded shadow maps),有时也被称为Parallel Split Shadow Maps。

如图所示,靠近相机区域使用了一个单独的阴影贴图,尺寸缩小,分辨率不变(总感觉说分辨率不变有歧义...)。
4.4.3 使用阴影层叠
在项目中,当我们使用音阴影层叠时,我们可以旋转使用0、2、4层叠。Unity会计算各层叠在相机视椎体内的位置。使用的层叠越多,阴影受透视混叠的影响就越小。但层叠越多,渲染开销也就越大,不过,相比在整个阴影中使用高分辨率的贴图,层叠的开销仍然要小。
若使用内置渲染管线,则在项目的质量设置窗口中配置每个质量级别的阴影层叠。如图:

若使用通用渲染管线(URP),则在渲染管线的Asset文件中设置阴影层叠。
若使用高清渲染管线(HDRP),则需要为每个Volume设置阴影层叠。
4.5 阴影问题解决方案
4.5.1 阴影性能
- 实时阴影具有相当高的渲染开销,任何可能投射阴影的游戏对象必须首先渲染到阴影贴图中,然后该贴图将用于渲染可能接收阴影的对象。
- Soft shadows比Hard Shadows有更大的渲染开销,但这只对GPU有较大影响,对CPU影响较小。
- 如果为复杂的几何体渲染实时阴影的成本过高,可以考虑使用低LOD网格。
- 当角色阴影性能开销较大时,还可以考虑将一个模糊的纹理应用到一个简单的Mesh或Quad上,然后将其放到角色下当做阴影,或者使用自定义的shader来创建阴影。
4.5.2 阴影暗斑
被光直接照射的表面有时看起来部分处于阴影中。这是因为应该准确地在阴影贴图中指定距离上的像素,其有时被计算到更远的距离了(这是使用阴影过滤或阴影贴图使用低分辨率图像造成的)。其结果是,一些像素处于阴影之中,而它们本应是被照亮的,产生了一种被称为"阴影暗斑(shadow acne)"的视觉效果。如图,在低分辨率阴影情况下,物体表明出现了一些类似波纹的东西。

4.5.3 光偏移设置
为了预防阴影暗斑,我们可以调整光偏移设置(Light Bias Settings)。
我们可以在阴影贴图中增加一个距离偏移,以确保边缘上的像素通过比较,或者我们可以沿着它的法线(normals)插入一点几何偏移。
在内置渲染管道中,当启用阴影时,我们可以在Light Inspector窗口中使用Bias和Normal Bias属性设置这些值。
不要将Bias值设置得太高,因为在投射它的GameObject附近的阴影区域有时会被错误地照亮。这导致了一个不连贯的阴影,使GameObject看起来好像在地面上飞行。如图:

同样地,将Normal Bias值设置得太高会使GameObject的阴影显得太窄,有种变小的感觉:

在某些情况下,Normal Bias会导致一种不必要的效果,称为"光出血(light bleeding)",即光线从附近的几何图形中渗出到应该阴影的区域。一个潜在的解决方案是将GameObject的Mesh Renderer组件上的Cast Shadows属性更改为Two sides。这有时会有所帮助,尽管它在渲染场景时可能会占用更多资源并增加性能开销。
关于Bias的值,一般需要合理的调整,以确保不发生不想要的效果,通常用眼睛来衡量正确的值比试图计算它更容易。
比如,如果设置不合理的偏移值(包括Bias、Normal Bias),就会导致如下情况:

如图,阴影中出现了一块空洞。而其本来的模样是这样的:

4.5.4 阴影平坠
为进一步预防阴影暗斑,我们正在使用一种被称为阴影平坠(Shadow pancaking)。这个想法是为了减少沿光照方向渲染阴影贴图时使用的光照空间范围。这样可以提高阴影贴图的精度,减少阴影暗斑。
阴影平坠原理介绍,原理图:

在上图中:
- 浅蓝色的圆圈代表阴影投射者,即产生阴影的物体。
- 深蓝色矩形代表原始光照空间
- 绿线表示优化后的近平面(将视锥体中不可见的所有阴影投射物排除在外)
将这些阴影投射物钳制在优化空间的近裁剪面(在顶点着色器中)。请注意,虽然这通常很有效,但对于穿过近裁剪面的大型三角形,这会带来瑕疵,如图:

在此情况下,只有蓝色三角形的一个顶点位于近裁剪面背后并被钳制到此处(由这个就看懂了,这个"钳制"含义:图中右侧可看到三角形顶点被强行往近裁剪面移动了)。但是,这会改变三角形的形状,并可能产生不正确的阴影。
我们可以从Quality窗口中调整 Shadow Near Plane Offset 属性以避免发生此问题。这将拉回近裁剪面(即图中往下移动)。但是,如果将此值设置得非常高,最终会引入阴影暗斑,因为它会提高阴影贴图需要在光照方向上覆盖的范围(即图中值越大近裁剪面越往下走)。或者,我们也可以拆分有问题的阴影投射三角形。
4.5.5 阴影不显示
如果我们发现一个或多个对象未投射阴影,则可以从以下几点来检查:
- 检查Quality窗口,看看对应的质量级别,是否启用了阴影。
- 检查对象的Mesh Renderer中Receive Shadows和Cast Shadows属性是否启用。
- 只有不透明对象才投射和接受阴影,因此使用内置透明着色器或粒子着色器的对象既不会投射也不会接受阴影。通常,我们可以使用透明镂空着色器代替具有"间隙"的对象,例如栅栏、植被等。自定义着色器必须采用像素光照并使用几何渲染队列。
- 使用顶点光照 (VertexLit) 着色器的对象不能接受阴影,但可投射阴影。
- 如果游戏对象的材质具有"无光照"类型的着色器,Unity 无法为这些游戏对象计算阴影。只有材质的着色器支持光照时,Unity 才能为材质计算阴影。
- 在内置渲染管道中,使用正向渲染路径(Forward Rendering Path),一些着色器只允许最亮的方向光投射阴影(特别是,这发生在Unity的内置着色器4.x版本)。如果我们想有一个以上的阴影投射光,那么我们应该使用延迟着色(Deferred Shading)渲染路径。我们可以通过使用fullforwardshadows表面着色器指令来启用我们自己的着色器来支持"完全阴影(full shadows)"。
5 全局光照
全局光照(Global Illumination,GI),考虑场景中直接来自光源的光照,同时又考虑经过场景中其他物体反射后的光照的一种渲染技术。GI可以有效地增强场景的真实感。毫无疑问,实时性的GI是非常耗费性能的,所以通常会选择进行预先计算。Unity中,GI有两种,第一种是实时GI(Enlighten Realtime Global Illumination),第二种是烘焙GI(Baked Global Illumination)。
- 实时GI:可以对静态物体(参与GI的物体,本身会变为静态状态)进行光线反射部分数据的预计算(光照贴图),在运行时,支持实时光线的改变(也会改变光照贴图)。但这样就会存在一定的延迟,不适合快速变化的灯光。所属系统:Enlighten Realtime Global Illumination系统。
- 烘焙GI:将全局光照信息提前计算,并烘焙到一张LightMap贴图(光照贴图)中不必实时计算,以此来节省性能资源。但相对的,光照就定死位置了,无法再发生变化(光照贴图无法改变)。烘焙GI有两种模式,一种是Baked模式只有烘焙光,另一种Mixed模式将包含烘焙光和实时光。所属系统:Lightmapper系统。
好了,到这里我们就知道了三种情况的光照,一种是Unity默认光照,一种是实时GI,一种是烘焙GI(两种模式)。
5.1 让物体参与GI
想要使用GI,首先要让物体能够参与到GI中,那么如何设置呢?如图:

选中物体,将其设置为静态,这里实际只需勾选图中的"Contribute GI"即可,勾选后物体变变为静态的,无法在运行时移动了(对于非静态物体也可以使用光照探针进行间接光处理,这里先不讲),但同时也可以参与GI了。
或者也可以在物体的MeshRender组件中设置,勾选"Contribute Global Illumination"即可,这个与我们设置的"Contribute GI"是会同步改变的,勾选一个,另一个就会自动勾选。

5.2 实时GI
实时计算直接光、间接光,生成的光照贴图辅助计算间接光。Window→Rendering→Lighting,打开Lighting面板。勾选"Realtime Global Illumination",表示在生成光照数据时,生成实时光照数据。之后选择我们的光源对象,将其Mode设置为Realtime。

然后点击Lighting面板的Generate Lighting即可(一般也会将这个操作称为"烘焙"),生成光照贴图。

PS:注意点击按钮右侧的倒三角,可在下拉列表中清除已经生成的光照数据。
之后我们可以在"Realtime Lightmaps"面板中看到生成的光照贴图,此光照贴图会随着光源的改变而改变,这里就不再演示了,可以在打开此窗口的同时,试一试调整光线颜色。

另外,还要注意生成的光照数据文件:

一般会自动生成一个同场景名的文件夹,来存放生成的数据。
5.2.1 演示
这里还是演示下吧。首先搭建一个全黑场景,涉及相机、环境光设置,如图:


这样以来,整个场景就暗下来了,这里我搭建了一个小房子(给了材质改了个颜色),外加一个方向光,修改为Realtime模式,整体场景如图:

接下来使用实时GI:

可以看到,在烘焙完实时GI后,房子内的细节瞬间就有了。然后我开始旋转光源,由于直接光、间接光都是实时的,可以看到阴影、房子内的细节都会随着光源的旋转而变化。
PS:
- 旋转光源,有时候会出现间接光变化不及时的问题,这是正常的,因为实时间接光较耗费性能,计算速度过慢导致有时候变化不及时。
- 还有一种就是旋转光源,但间接光不变化,不变化就是不变化。这就是BUG,重启Unity就好。这BUG搞了两个多小时没找出问题,重启解决了,感觉可能跟GI缓存有关,但我又没证据。
5.3 烘焙GI
这里我们需要勾选"Baked Global Illumination",表示在生成光照数据时,生成烘焙光照数据。这里若不需要实时GI的话可以取消"Realtime Global Illumination"的勾选,这里我们取消,方便案例说明。之后同样,我们需要去设置光源的Mode,不过这里有两种可选:Mixed、Baked。
5.3.1 Mixed
光源Mode选择Mixed表示混合,即包含实时光与烘焙光。Lighting面板的Lighting Mode为默认的Shadowmask时(目前只讨论这个),我们点击"Generate Lighting",只会生成间接光 的烘焙光照数据,直接光此时为实时计算的,即实时光照。我们可以看下生成的光照数据:

即,无实时GI光照贴图。

即,有烘焙GI光照贴图。

Project中生成的光照数据文件。
5.3.2 Mixed演示
场景搭建与实时GI演示里一样,这里使用mixed烘焙GI来看看效果,由于烘焙时间过长,这里直接展示烘焙好的场景:

如图所示,是已经烘焙好有细节的场景,由于直接光是实时的、间接光是定死的,所以随着光源的旋转可以看到阴影是实时变化的,但房子左侧地面上的光(间接光造成的)却没有变化,即使其侧已经没有光照了地面却依旧在发亮。实际内部细节也没有变化,这不过这里可能看不太清楚。
5.3.3 Baked
光源Mode选择Mixed表示纯烘焙,即只包含烘焙光。Lighting面板的Lighting Mode为默认的Shadowmask时,我们点击"Generate Lighting",会生成直接光 、间接光的烘焙光照数据。
5.3.4 Baked演示
场景搭建与实时GI演示里一样,这里使用baked烘焙GI来看看效果,由于烘焙时间过长,这里直接展示烘焙好的场景:

如图所示,是已经烘焙好有细节的场景,由于直接光、间接光是定死的,所以随着光源的旋转,什么都没有变化,阴影不变,细节也不变。
5.4 Lighting窗口
Lighting 窗口是 Unity 光照功能的主要控制点。使用 Lighting 窗口调整与场景中的光照有关的设置,并根据质量、烘焙时间和存储空间来优化预计算的光照数据。
5.4.1 相关 API
可以使用 LightingSettings 和 Lightmapping API,通过脚本执行 Lighting 窗口中提供的许多函数。
5.4.2 内部包含的窗口
- Scene。
- Environment。
- Realtime Lightmaps。
- Baked Lightmaps。
- Probe Volumes,高清渲染管线(HDRP)独有。
- Control Area,在Lighting窗口底部。
5.4.3 Scene
此窗口中显示的信息是分配给当前激活场景的光照设置资源(Lighting Settings Asset)文件中的信息。如没有给当前激活场景分配此文件,则会显示默认光照设置(LightingSettings)对象的信息(一个内置的只读对象)。

5.4.3.1 Lighting Settings
- Lighting Settings Assets:光照设置资源文件。光照设置就是此Lighting面板中的各种设置,设置的内容都会被记录到此属性上的资源文件中。我们可以在这里替换文件。我们也可以点击New按钮创建多个资源文件,分别存储不同的光照设置,点击Clone按钮可以复制当前资源文件。
5.4.3.2 Realtime Lighting
本节包含了与 Enlighten Realtime Global Illumination系统相关的设置。
- Realtime Global Illumination:勾选后,启用实时GI系统,在Generate Lighting时会生成实时光照数据。
- Realtime Environment Lighting:勾选后,使用实时GI系统来计算、更新环境光。只有在"Baked Global Illimination"启用后才可设置,若没有启用,则此属性默认强制勾选。
- Indirect Resolution:指定用于实时光照贴图的每个单元的纹理数。增加这个值可以提高光图质量,但也会增加渲染时间。
5.4.3.3 Mixed Lighting
本节包含在使用此Lighting Settings Asset的场景中影响Baked光和Mixed光行为的设置。
- Baked Global Illumination:勾选后,启用烘焙GI系统,在Generate Lighting时会生成烘焙光照数据。
- Lighting Mode:光照模式。可选项有Shadowmask、Baked Indirect、Subtractive。
- Shadowmask:对所有Mixed模式的灯光使用此模式。提供实时直接照明,而间接光被烘烤成光照贴图和光照探针。这种模式结合了实时和烘烤阴影,效果较好。
- Baked Indirect:对所有Mixed模式的灯光使用此模式。提供实时直接照明,而间接光被烘烤成光照贴图和光照探针。实时提供阴影。
- Subtractive:Mixed模式的灯光为静态物体提供直接和间接照明。动态对象接收实时直接照明,并使用定向光投射阴影。性能最好,效果最差。
5.4.3.4 Lightmapping Settings
-
Lightmapper:光照映射器。选择使用什么来计算场景中的光照贴图。有CPU、GPU两种选择。
-
Progressive Updates:启用此设置可使渐进光照映射器将更改应用于 Scene 视图中当前可见的纹素,然后将更改应用于视图外的纹素。
-
Importance Sampling:启用此选项以使用多重重要性采样对环境进行采样。当生成lightmaps时,这通常会导致更快的收敛,但在某些低频环境中可能会导致嘈杂的结果。这在默认情况下是禁用的。
-
Direct Samples:这个设置控制CPU、GPU采样数量,这些采样将用于计算直接光照。只能设置为2的幂。最大值为2的30次方。
-
Indirect Samples:这个设置控制CPU、GPU采样数量,这些采样将用于计算间接光照。只能设置为2的幂。最大值为2的30次方。
-
Environment Samples:环境样本属性决定了Unity向天空盒发射的环境光线的总数,以直接收集光线。Unity根据上下文从光贴图纹理或光探针位置发射这些光线。默认值为256。更高的值可能会产生更平滑的结果,但代价是烘烤时间的增加。只能将滑块设置为2的幂,最小值为1,最大值为2048。在HDR天空盒的场景中,通常需要更多的样本来减少最终光图或探头中的噪点。包含明亮的奇点(如太阳)或具有显著对比度的高频细节(如背光云)的天空盒场景也受益于更高数量的样本。
-
Light Probe Sample Multiplier:控制多少采样用于光照探针,这里设置的是一个乘数,会影响最终所用采样数。更高的值提高光照探针的质量,但他们将需要更长的烘烤时间。要启用此功能,请转到Project Settings > Editor,并禁用"Use legacy Light Probe sample counts"。此项默认值为4。
-
Max Bounces:Lightmapper所包含的直接光的最大反射次数。默认值2,范围[0,100]。设置为10适用于大多数场景,高于10的值可能会导致烘焙时间明显延长。每次反弹都会增加烘焙场景所需的计算资源。对室内场景可使用较高的值,对室外场景和有许多明亮表面的场景可以使用较低的值。
-
Filtering:过滤。配置Progressive Lightmapper对光照贴图进行后处理的方式,以限制噪点。对于光照贴图的后处理,光照贴图被分成直接遮挡,间接遮挡和环境遮挡三种类型,Unity分别应用后处理,然后将它们组合成一个单一的光照贴图。直接:任何从光源直接到达传感器(通常是相机)的光。间接:任何从光源间接到达传感器的光。这通常适用于从其他游戏对象反射的光。环境遮挡:光照系统计算的任何环境光。可配置选项:
-
None:选择此选项,对光照贴图不进行后处理去噪。
-
Auto:使用平台相关的预设来对光照贴图进行后处理。如果开发机器满足运行OptiX (NVIDIA OptiX AI-Accelerated Denoiser)的要求,Progressive Lightmapper使用高斯滤波器去噪器,该滤波器对所有目标具有1 texel(纹理)半径。如果开发机器不能运行OptiX,则Progressive Lightmapper会退回到OpenImageDenoise。
-
Advanced:为每种类型的光照贴图目标手动配置选项。目标类型有直接遮挡、间接遮挡和环境遮挡。有关详细信息,请参阅。
-
-
-
Lightmap Resolution:指定用于光照贴图的每个单元的纹理数。增加这个值可以提高光照贴图质量,但也会增加烘焙时间。注意,加倍这个值会导致texels的数量翻四倍,因为它决定了光照贴图的高度和宽度。
-
Lightmap Padding:决定在光照贴图中分离形状之间的分离度(以texel为单元)。
-
Max Lightmap Size:最大光照贴图尺寸。默认1024。
-
Lightmap Compression:光照贴图压缩级别。
-
Ambient Occlusion:控制烘焙环境遮挡中表面的相对亮度。这只适用于我们用来烘焙光照的光照映射器所计算的间接照明。如果启用此属性,将会提供额外的三个设置:最大距离,间接贡献,和直接贡献。对于所有三种设置,更高的值表示遮挡和完全照亮区域之间的对比度更大。(三个设置官方文档写得很清楚,这里就不写了)
-
Directional Mode:使光照贴图能够存储物体表面上每个点的主要入射光的特征信息。可选项:
-
Directional:在此模式下,Unity生成第二个光照贴图来存储入射光的主要方向。这使得漫射法线贴图材质可以与全局照明系统一起工作。着色器在渲染过程中对两种光照贴图纹理进行采样。因此,定向模式需要的显存大约是非定向模式的两倍,以存储额外的光照贴图数据。此选项在烘焙时将会耗费更多性能。在SM2.0硬件或使用GLES2.0时,方向光照贴图无法解码。
-
Non-directional:此模式光照贴图只包含一个纹理。因此,它们比Directional光照贴图需要更少的显存和存储空间,并且在着色器中解码速度更快。但这些优化降低了视觉质量。
-
-
Albedo Boost:指定Unity在表面之间反射的光量。取值范围为1 ~ 10。增加这个值将会把用于间接光计算的反照率值拉向白色。默认值1在物理上是准确的。
-
Indirect Intensity:决定存储在实时和烘焙光照贴图中的间接光的亮度。这是一个介于0和5之间的值。大于1的值增加了间接光的强度,小于1的值减少了间接光的强度。默认值为1。
-
Lightmap Parameters:此为一个资源对象,存储了与烘焙GI相关的设置值。编辑器提供了几个默认的光照贴图参数资源可供选择,我们也可以使用选项下拉框中的Create New选项创建自己的光照贴图参数资源。
5.4.3.5 Workflow Settings
-
GPU Baking Device:使用此属性更改 Unity 用于预计算光照数据的 GPU。
-
Light Probe Visualization:用于过滤哪些光照探针显示在 Scene 视图中。默认值为 Only Probes Used By Selection。三种可选项:
-
Only Probes Used By Selection:只有影响当前选择的光照探针才会显示在 Scene 视图中。
-
All Probes No Cells:所有光照探针都将显示在 Scene 视图中。
-
All Probes With Cells:所有光照探针都将显示在 Scene 视图中,还会显示用于光照探针数据插值的四面体。
-
None:任何光照探针都不显示在 Scene 视图中。
-
Display Weights:启用此复选框时,Unity 将从用于有效选择的光照探针到用于插值的四面体上的位置绘制一条线。这是一种调试探针插值和放置问题的方法。
-
Display Occlusion:启用此复选框时,如果 Lighting Mode 设置为 Shadowmask,则 Unity 将显示光照探针的遮挡数据。
-
Hightlight Invalid Cells:高亮不能被用于光照探针插值的无效四面体。
-
-
Recalculate Environment Lighting:重新计算环境光照。勾选后,如果没有生成预先计算的照明数据,Unity会使用SkyManager自动计算所有开放场景的环境照明。
5.4.4 Environment
包含相关当前场景的环境光照效果的设置。可配置内容取决于我们的项目使用的渲染管线。
5.4.4.1 Environment
Environment 部分包含与光照相关的设置和控件,这些设置和控件适用于当前场景中的环境光照,例如天空盒、漫射光照和反射。
-
Skybox Material:天空盒材质,它出现在场景中的所有其他对象后方,用于模拟天空或其他遥远的背景。使用此属性可选择要用于场景的天空盒。默认值是内置的默认天空盒 (Default Skybox)。
-
Sun Source:选择一个光源作为场景中的太阳。Unity使用这个光来模拟天空盒和场景中太阳的位置和强度的效果。如果你将此设置为None, Unity将场景中最亮的方向光视为太阳。若所选光源的渲染模式属性设置为不重要,则其不会影响天空盒。
-
Realtime Shadow Color:定义Unity在Subtractive照明模式下渲染实时阴影时使用的颜色。
-
Environment Lighting:此部分包含可影响当前场景中的环境光的相关设置。
- Source:定义场景中环境光的光源颜色。默认值为Skybox。可选有Skybox、Gradient、Color。Skybox:使用Skybox Material中设置的天空盒颜色来确定来自不同角度的环境光。这可以实现比Gradient更精细的效果。Gradient:可为来自天空、地平线和地面的环境光选择单独的颜色,并在它们之间平滑混合。Color:对所有环境光使用单调颜色。
-
Environment Reflections:此部分包含反射探针烘焙的全局设置,以及影响全局反射的设置。
-
Source:使用此设置来指定是否使用Skybox进行反射效果,或是选择Cubemap。默认值是Skybox。Skybox:选择此选项可使用天空盒作为反射源。Custom:选择此选项可以使用Cubemap资源或类型为cube的RenderTexture进行反射。
-
Resolution:使用此属性可设置用于反射的天空盒的分辨率。仅当Source设置为Skybox时,此属性才可见。
-
Cubemap:使用此属性可设置用于反射的Cubemap。仅当Source设置为Custom时,此属性才可见。
-
Compression:使用此属性可定义是否压缩反射纹理。默认设置是Auto。Auto:如果压缩格式合适,则压缩反射纹理。Uncompressed:反射纹理以非压缩状态存储在内存中。Compressed:压缩纹理。
-
Intensity Multiplier:反射源在反射对象中可见的程度。可以理解为反射强度。
-
Bounces: 当来自一个对象的反射随后被另一个对象反射时,便发生反射反弹。使用此属性可设置反射探针评估对象之间来回反弹的次数。如果设置为 1,则 Unity 只会考虑初始反射(即上面Source属性中指定的天空盒和Cubemap)。
-
5.4.4.2 Other Settings
Other Settings 部分包含雾(Fog)、光环(Halo)、光晕(Flare)、剪影(Cookies)的设置。
-
Fog:在场景中启用或禁用雾效。请注意,此模式无法用于延迟渲染路径。勾选后会出现额外三个属性。
-
Color:设置Unity在场景中所绘制的雾的颜色。
-
Mode:定义雾化效果随着与摄像机距离变化而积累的方式。有Linear、Exponential、Exponential Squared。Linear:雾效强度随着距离线性增加,同时具有两个可设置属性,Start:设置在距离摄像机多远时开始雾效,End:设置在距离摄像机多远时雾效完全遮挡场景游戏对象。Exponential: 雾效强度随着距离呈指数增加,有一个可设置属性,Density:用于控制雾效的强度,雾效强度随着Density增加而增加。Exponential Squared:雾效强度随着距离更快速增加(指数和平方),有一个可设置属性,Density:用于控制雾效的强度。雾效强度随着Density增加而增加。
-
-
Halo Texture:光环纹理。设置要用于在光源周围绘制光环的纹理。
-
Halo Strength:光环强度。定义光源周围光环的可见性,值在 0 到 1 之间。
-
Flare Fade Speed:光晕过渡速度。定义最初出现镜头光晕之后从视图中淡出的时间(以秒为单位)。默认情况下,该值设置为3。(PS:名字是Speed,文档却说设置值表示时间,真自由啊。)
-
Flare Strength:光晕强度。定义光源下镜头光晕的可见性,值在 0 到 1 之间。
-
Spot Cookie:设置你想要用于聚光灯的Cookie纹理(即,聚光灯默认情况下的Cookie)。默认为soft。若要选择soft,请选择None(即为soft)。
5.4.5 Realtime Lightmaps
显示实时GI系统生成的所有光照贴图。更具体的,显示了当前场景中由Enlightenment实时全局照明系统生成的所有光照贴图。如果项目中没有启用"Realtime Global Illumination",则此窗口将为空。
5.4.6 Baked Lightmaps
显示烘焙GI系统生成的所有光照贴图。更具体的,显示了由Lightmapper为当前场景生成的所有光照贴图,和光照数据资源(Lighting Data Asset)。如果我们使用场景视图绘制模式(Scene view Draw Modes)来预览光照映射,那么这个窗口将还包含Unity为预览生成的临时光照贴图。如果项目中未启用"Baked Global Illumination",则该窗口为空。
5.4.7 Probe Volumes
此窗口包含与Probe Volumes相关的设置。只有在项目中使用HDRP时才会出现此窗口。有关更多信息:Probe Volumes。
5.4.8 Control Area
用于预计算光照数据的控件,其位于 Lighting 窗口的底部。
-
GPU Baking Device:使用这个来改变Unity用于预计算光照数据的GPU。此属性仅在使用GPU Progressive Lightmapper后端时可见。
-
GPU Baking Profile:在此属性中选择的配置文件定义了GPU Lightmapper如何将光照贴图分解为更小的块(tile)以减少GPU内存使用。选择自动配置文件后,Unity根据最大光照贴图的尺寸来选择tile大小,同时仍然以良好的GPU利用率为目标。最高性能(Highest Performance)和高性能配置文件(High Performance profiles)强制所有光照贴图使用一个更高的固定的tile尺寸。低内存使用(Low Memory Usage)和最低内存使用配置文件(Lowest Memory Usage profiles)强制所有光照贴图使用一个更低的固定的tile尺寸。更小的tile占用更少的GPU内存,以降低GPU利用率为代价,导致更长的烘烤时间。此属性仅在使用GPU Progressive Lightmapper时可见。
-
Generate Lighting:点击此按钮来预先计算所有打开场景的光照数据。这些数据包括"Baked Global Illumination"系统光照贴图、"(Enlighten )Realtime Global Illumination"系统光照贴图、光照探针、反射探针。在点击按钮开启烘焙流程后,再进行编辑操作不会影响烘焙光照。
-
单击Generate Lighting右侧的下拉菜单,然后单击Bake Reflection Probes,只烘焙所有打开场景中的反射探针。单击Generate Lighting右侧的下拉菜单,
-
单击Generate Lighting右侧的下拉菜单,然后点击Clear Baked Data,清除所有打开场景中的所有预先计算的光照数据,但不会清除GI缓存(Global Illumination cache)。
-
6 光照设置资源
光照设置资源(Lighting Settings Asset)是LightingSetting类的一个保存实例,该类存储了Baked Global Illumination和Enlighten Realtime Global Illumination系统的数据。当使用这两个系统中一个或两来预计算光照数据时,Unity会使用此类中存储的数据来进行预计算。
我们可以将一个Lighting Settings Asset或LightingSetting类的实例分配给多个场景,很容易的就让多场景使用相同的光照设置。
6.1 创建Asset文件
三种创建方式,第一种:

这种方式会在当前Project窗口目录中创建一个Asset文件。
第二种:

这种方式会在当前Project中创建一个Asset文件,然后直接分配给当前激活的场景。也可以点击Clone按钮复制当前激活的场景的Asset文件,复制的文件会放在当前Project中,并直接分配给当前激活的场景。
第三种:
我们还可以从脚本创建Lighting Settings Asset。为此,需要在脚本中创建一个 LightingSettings 类的实例并将其保存到磁盘,或将其指定给场景并保存该场景。有关更多信息和代码示例,请参阅 LightingSettings API 文档。
6.2 将Asset设置给场景
在Lighting窗口中设置,就在上面第二种创建方式那个属性那里放Asset文件即可。只需要注意一点,Lighting面板对应的是激活场景,所以打开多个场景的时候只需要把我们要设置的场景调为激活状态即可。
还有一种就是脚本设置了,从脚本将Lighting Settings Asset指定给激活场景。比如加载Lighting Settings Asset以获取 LightingSettings 类的实例,然后使用Lightmapping.lightingSettings API将该LightingSettings实例指定给激活场景。有关更多信息和代码示例,请参阅 LightingSettings API 文档。
6.3 查看和编辑Asset的属性
有三种方式:Asset文件的Inspector面板、Lighting窗口的Scene窗口、脚本访问。
Inspector面板:

Lighting窗口的Scene窗口:

脚本访问:
加载Lighting Settings Asset以获得LightingSettings类的实例,并访问其属性。有关更多信息和代码示例,请参阅LightingSettings API documentation。
6.4 默认LightingSettings数据
当一个场景没有Lighting Settings Asset分配给它时,Unity使用该场景的默认LightingSettings对象。默认的LightingSettings对象是LightingSettings类的一个内部只读实例。
如果一个场景使用了默认LightingSettings对象,那么我们不能对此场景的LightingSettings数据进行任何更改,但是Unity可以使用此设置执行烘焙。
总之,想修改,就别用默认的。
6.5 属性介绍
见全局光照中的Lighting窗口介绍。【链接】
6.6 Lighting Mode
Lighting Mode 决定使用 Lighting Settings Asset 的场景中的说有混合光源的行为(烘焙的混合光)。可用的模式有:Baked Indirect、Shadowmask、Subtractive。Lighting Mode在Lighting面板中,位置如图:

6.6.1 Baked Indirect
当我们设置此模式时,混合光的行为就如同实时光一样,但着有额外的好处:将间接光烘焙到光照贴图中。此时混合光所照亮物体投射的阴影是实时的,且阴影最大距离是在项目中定义的阴影距离(Shadow Distance)。
6.6.1.1 渲染管线支持
有关跨渲染管线支持Baked Indirect Lighting Mode的更多信息,请参阅render pipeline feature comparison 。
6.6.1.2 混合光行为
点亮的动态物体能接收:
-
实时直接光照。
-
烘焙间接光照(使用光照探针)。
-
来自动态游戏对象的(实时)阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
-
来自静态游戏对象的实时阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
点亮的静态物体能接收:
-
实时直接光照。
-
烘焙间接光照(使用光照贴图)。
-
来自动态游戏对象的实时阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
-
来自静态游戏对象的实时阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
6.6.1.3 阴影与运行时性能
在此模式下,所有来自混合光的阴影都是实时的,这可能会影响性能。不过我们可以使用阴影距离属性来限制 Unity 绘制实时阴影的最大距离,从而降低这种影响。
6.6.1.4 运行是改变光属性
在 Baked Indirect 光照模式下,可以在运行时巧妙地更改混合光源的属性。此类更改会影响混合光源对场景的实时直接光照,但不会影响混合光源对场景的烘焙间接光照。这样便可以将间接光照的优点与实时光照的某些动态功能结合起来。由于缺少预先计算的阴影(相对的意思就是阴影是实时的),因此在 Baked Indirect 光照模式下效果特别好。
在运行时对光源属性进行更改必须特别小心,只进行微小的更改,确保不会引起实时直接光照和烘焙间接光照之间不切实际的组合。例如,如果将红色混合光源烘焙到光照贴图中,然后在运行时将其颜色从红色更改为绿色,则直接光照将为绿色,但烘焙到光照贴图中的间接光照仍为红色。此情况同样适用于在运行时移动混合光源:直接光照将跟随光源的新位置,但间接光照将保持在光源烘焙位置。
以下视频举例说明了如何略微修改混合光源而不会导致间接光照出现明显不一致问题:https://youtu.be/XN6ya31gm1I(请自带魔法)
6.6.2 Shadowmask
Shadowmask模式与Baked Indirect模式类似,此模式将实时直接光照与烘焙间接光照相结合。但是,Shadowmask模式不同于Baked Indirect的地方是:Shadowmask渲染阴影。Shadowmask模式使Unity在运行时结合烘焙和实时阴影并在远处渲染阴影成为可能。它通过使用一个额外的光照贴图纹理,即阴影遮罩(shadow mask),并通过在光照探针中存储额外的信息来实现这一点。Unity为烘焙的阴影(即前面说的渲染的阴影)生成阴影遮罩和光照探针遮挡数据。(PS:我的理解是相比Baked Indirect,其多了阴影遮罩、光照探针的使用,由此可以在阴影距离之外渲染阴影。)
Shadowmask照明模式在所有照明模式中提供最高保真度的阴影,但具有最高的性能成本和内存要求。它适合在高端或中档硬件上渲染可以看到远处GameObjects的逼真场景,例如开放世界。
6.6.2.1 渲染管线支持
有关跨渲染管线支持Shadowmask Lighting Mode的更多信息,请参阅render pipeline feature comparison 。
6.6.2.2 Shadowmask质量设置
在Quality面板中可以设置Shadowmask的模式:
-
Distance Shadowmask:其以更高的性能成本提供更高的保真度阴影。
-
Shadowmask:其以较低的性能成本提供较低的保真度阴影。

6.6.2.3 混合光行为
Shadowmask质量设置为Distance Shadowmask模式下:
混合光源照亮的动态游戏对象将接收:
-
实时直接光照。
-
烘焙间接光照(使用光照探针)。
-
来自动态游戏对象的实时阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
-
来自静态游戏对象的实时阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
-
来自静态游戏对象的烘焙阴影(使用光照探针),超过阴影距离 (Shadow Distance)。
混合光源照亮的静态游戏对象将接收:
-
实时直接光照。
-
烘焙间接光照(使用光照贴图)。
-
来自动态游戏对象的实时阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
-
来自静态游戏对象的实时阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
-
来自静态游戏对象的烘焙阴影(使用阴影遮罩),超过阴影距离 (Shadow Distance)。
Shadowmask质量设置为Shadowmask模式下:
混合光源照亮的动态游戏对象将接收:
-
实时直接光照。
-
烘焙间接光照(使用光照探针)。
-
来自动态游戏对象的实时阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
-
来自静态游戏对象的烘焙阴影(使用光照探针),不超过以及超过阴影距离 (Shadow Distance)。
混合光源照亮的静态游戏对象将接收:
-
实时直接光照。
-
烘焙间接光照(使用光照贴图)。
-
来自动态游戏对象的实时阴影(使用阴影贴图),不超过阴影距离 (Shadow Distance)。
-
来自静态游戏对象的烘焙阴影(使用阴影遮罩),不超过以及超过阴影距离 (Shadow Distance)。
6.6.2.4 阴影与运行时性能
同上,使用阴影距离属性来限制 Unity 绘制实时阴影的最大距离。
6.6.2.5 阴影遮罩实现详细信息
在运行时,Unity 使用阴影遮罩来确定某个像素是否在阴影中。阴影遮罩纹理包含有关烘焙光源的遮挡信息。该纹理与相应的光照贴图共享相同的 UV 布局和分辨率。还针对每个纹素包含最多四个光源的遮挡信息(以 RGBA 格式存储)。
如果超过四个光源发生重叠,则多余光源会回退至烘焙光照 (Baked Lighting)。烘焙系统会决定哪个光源回退至烘焙光照,并在各烘焙之间保持一致,除非我们修改其中某个重叠的光源。光照探针也会接收最多四个光源的相同信息。
Unity 将独立于接收阴影的对象来计算光源重叠。因此,一个对象可受到全部来自同一个阴影遮罩/探针通道的十个不同混合光源的影响,只要这些光照包围体在空间中的任何点都不重叠即可。如果某些光源重叠,则 Unity 会使用更多通道。如果某个光源确实发生重叠而所有四个通道都在使用中,则该光源将回退至完全烘焙。【?没太懂...】
6.6.3 Subtractive
在 Subtractive 光照模式下,场景中的所有混合光源都提供烘焙直接光照和间接光照。Unity 将静态游戏对象投射的阴影烘焙到光照贴图中。除了烘焙阴影外,一种方向光(称为主方向光)还为动态游戏对象提供实时阴影。
因为阴影被烘焙到光照贴图中,所以 Unity 在运行时缺少将烘焙阴影和实时阴影准确地结合在一起所需的信息。但是,Unity 提供了 Realtime Shadow Color 属性来减少光照贴图的影响,从而在烘焙阴影和实时阴影之间创建正确的混合视觉效果。还可以调整颜色来实现某种艺术风格。
Subtractive 光照模式在低端硬件上非常有用,因为低端硬件需要注重性能,并且只需要一个实时阴影投射光源。这种光照模式不会提供特别逼真的光照效果,而是更适合风格化美学,例如卡通风格。
6.6.3.1 渲染管线支持
有关跨渲染管线支持Subtractive Lighting Mode的更多信息,请参阅render pipeline feature comparison 。
6.6.3.2混合光行为
混合光源照亮的动态游戏对象将接收:
-
实时直接光照
-
烘焙间接光照(使用光照探针)
-
来自主方向光照亮的动态游戏对象的实时阴影,使用阴影贴图,不超过阴影距离 (Shadow Distance)
-
来自静态游戏对象的(烘焙)阴影(使用光照探针)
混合光源照亮的静态游戏对象将接收:
-
烘焙直接光照(使用光照贴图)
-
烘焙间接光照(使用光照贴图)
-
来自主方向光照亮的动态游戏对象的实时阴影,使用阴影贴图,不超过阴影距离 (Shadow Distance)
-
来自静态游戏对象的烘焙阴影(使用光照贴图)
6.6.3.3 更改阴影颜色
将场景的 Lighting Mode 设置为 Subtractive 时,Unity 将在 Lighting 窗口中显示 Realtime Shadow Color 属性。Unity 将实时阴影与烘焙阴影结合在一起时将使用此颜色。更改此值可以近似于场景内间接光照的颜色,使实时阴影与烘焙阴影更好地匹配。(PS:在Lighting窗口的Enviroment窗口中可找到此属性,而且也不是必须设置为Subtractive才显示。)
6.6.3.4 主方向光
Unity 会自动在场景中选择强度值最高的方向光作为主方向光。
7 Light Explorer窗口
7.1 窗口介绍
在 Light Explorer 窗口中可选择和编辑光源。要从菜单中打开 Light Explorer 窗口,请导航至 Window > Rendering > Light Explorer。窗口如图:

使用面板顶部的四个选项卡来查看当前场景中的灯光、2D灯光、反射探针、光照探针和静态放射(比如自发光材质)的设置,可编辑的参数是每种组件类型最常用的字段。使用搜索字段可在每个选项卡中筛选名称。我们也可以勾选Isolate Selection复选框,这样只有我们在场景中选中的对象才会显示到面板中,或是勾选Show Inactive Objects,在列表中显示那些被隐藏的对象。
7.2 窗口扩展
通过 Light Explorer 扩展,可以创建自定义版本的 Light Explorer 窗口。可以将这种扩展用于调整 Light Explorer 窗口的功能,以便其可处理"可编程渲染管线 (SRP) "或者"高清渲染管线的自定义光源"。
在 Light Explorer 窗口中,可以看到场景中的所有光源并可编辑它们的属性。使用此扩展,可以通过多种方式扩展当前窗口。例如,可以执行以下操作:
-
更改选项卡(从简单地更改选项卡名称到添加我们自己的自定义选项卡)以显示不同类型的游戏对象的列表。例如,如果要显示我们自定义的反射探针的属性信息,这将很有用。
-
更改选项卡上的列(同样从更改名称到添加您自己的自定义列),这里列就是指属性。例如,我们想要查看光源的其他属性。
7.2.1 扩展方法
要扩展 Light Explorer,可以继承自:
-
ILightingExplorerExtension
接口,然后重写GetContentTabs
方法。 -
DefaultLightingExplorerExtension
类(继承自ILightingExplorerExtension
)。此类提供窗口中已经存在的所有内容。如果只希望重写选项卡的数量、每个选项卡的标题或要显示的光源,请使用此选项。要了解如何以这种方式扩展 Light Explorer,请参阅下面的示例(下面代码是官方文档里的,这里我就不深入看了,只粘贴上来)。
下面的示例展示了如何扩展默认的 Light Explorer 类以仅显示光源的名称 (Name) 列,以及如何更改选项卡的数量。在我们自己的实现中,可以根据需要重写任意数量的方法。以下示例显示了光源的名称列:
cs
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;
[SupportedOnRenderPipeline(typeof(ExampleRenderPipelineAsset))]
public class SimpleExplorerExtension : DefaultLightingExplorerExtension
{
private static class Styles
{
public static readonly GUIContent Name = EditorGUIUtility.TrTextContent("Name");
}
protected override LightingExplorerTableColumn[] GetLightColumns()
{
return new[]
{
new LightingExplorerTableColumn(LightingExplorerTableColumn.DataType.Name, Styles.Name, null, 200), // 0: Name
};
}
}
以下示例仅显示光源的名称和启用状态,并隐藏 Emissive Materials 选项卡(仅显示 3 个选项卡,而不是 4 个)(PS:这不是显示4个吗?)
cs
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;
[SupportedOnRenderPipeline(typeof(ExampleRenderPipelineAsset))]
public class ComplexLightExplorerExtension : DefaultLightingExplorerExtension
{
private static class Styles
{
public static readonly GUIContent Name = EditorGUIUtility.TrTextContent("Name");
public static readonly GUIContent Enabled = EditorGUIUtility.TrTextContent("Enabled");
}
protected override UnityEngine.Object[] GetLights()
{
return Resources.FindObjectsOfTypeAll<Light>();
}
protected override LightingExplorerTableColumn[] GetLightColumns()
{
return new[]
{
new LightingExplorerTableColumn(LightingExplorerTableColumn.DataType.Name, Styles.Name, null, 200), // 0: Name
new LightingExplorerTableColumn(LightingExplorerTableColumn.DataType.Checkbox, Styles.Enabled, "m_Enabled", 25), // 1: Enabled
};
}
public override LightingExplorerTab[] GetContentTabs()
{
return new[]
{
new LightingExplorerTab("Lights", GetLights, GetLightColumns, true),
new LightingExplorerTab("2D Lights", Get2DLights, Get2DLightColumns, true),
new LightingExplorerTab("Reflection Probes", GetReflectionProbes, GetReflectionProbeColumns, true),
new LightingExplorerTab("Light Probes", GetLightProbes, GetLightProbeColumns, true),
new LightingExplorerTab("Static Emissives", GetEmissives, GetEmissivesColumns, false),
};
}
}
7.2.2 有用的类和方法
下面列出了可用于扩展 Light Explorer 的类和方法(就上面说的那两个继承类):
ILightingExplorerExtension:
cs
public virtual LightingExplorerTab[] GetContentTabs();
public virtual void OnEnable() {}
public virtual void OnDisable() {}
DefaultLightingExplorerExtension(继承自 ILightingExplorerExtension):
cs
public virtual LightingExplorerTab[] GetContentTabs();
public virtual void OnEnable() {}
public virtual void OnDisable() {}
protected virtual UnityEngine.Object[] GetLights();
protected virtual LightingExplorerTableColumn[] GetLightColumns();
protected virtual UnityEngine.Object[] GetReflectionProbes();
protected virtual LightingExplorerTableColumn[] GetReflectionProbeColumns();
protected virtual UnityEngine.Object[] GetLightProbes();
protected virtual LightingExplorerTableColumn[] GetLightProbeColumns();
protected virtual UnityEngine.Object[] GetEmissives();
protected virtual LightingExplorerTableColumn[] GetEmissivesColumns();
8 光照映射
光照映射是预先计算场景中表面亮度的过程,并将结果存储在称为"光照贴图"的纹理中供以后使用。

左:一个简单的光照映射场景。右:Unity 生成的光照贴图纹理。请注意捕获阴影和光照信息的方式。
光照贴图可以包含直射光和间接光。该光照纹理可与颜色(反照率)和浮雕(法线)之类的对象表面信息一起使用,通过与材质相关联的着色器。烘焙到光照贴图中的数据无法实时更改。实时光可以在光照贴图场景上叠加和使用,但不能交互式地更改光照贴图本身。通过这种方法,我们用在游戏中移动灯光的能力来换取潜在的性能提升,以适应功能较弱的硬件,如移动平台。
Unity通过 Progresssive Lightmapper来烘焙光照贴图。
8.1 Progressive Lightmapper
Progressive Lightmapper是一个快速的基于路径跟踪的Lightmapper系统,其提供了能在 Editor 中逐渐刷新的烘焙光照贴图和光照探针。要求不重叠的 UV 具有较小的面积和角度误差,以及棋盘格图表之间有足够的填充。
Progressive Lightmapper采取了一个短暂的准备步骤来处理几何体与实例的更新,同时生成 G-buffer 和图表遮罩。然后,它会立即生成输出,并随着时间的推移逐步细化输出,以实现更完善的交互式照明工作流。此外,烘焙时间更加可预测,因为Progressive Lightmapper在烘焙时提供估计时间。
Progressive Lightmapper还可单独为每个纹素(texel)分别以光照贴图分辨率烘焙全局光照 (GI),无需采用上采样方案或依赖任何光照强度缓存或其他全局数据结构。因此,Progressive Lightmapper具有强大的功能,并允许我们烘焙光照贴图的选定部分,从而更快测试和迭代场景。
如需观看介绍交互式工作流程的深入视频,请参阅 Unity 的视频演练:开发中 - 渐进光照贴图 (In Development - Progressive Lightmapper) (YouTube)。
8.1.1 CPU、GPU Progressive Lightmapper
可以在Progressive Lightmapper的两个后端之间进行选择。Progressive CPU Lightmapper是使用计算机 CPU 和系统 RAM 的后端。Progressive GPU Lightmapper是使用计算机 GPU 和 VRAM 的后端。
8.1.2 渲染管线支持
有关跨渲染管线支持Progressive Lightmapper的更多信息,请参阅render pipeline feature comparison。
8.1.3 平台兼容性
苹果硅版本的Unity Editor与CPU Progressive Lightmapper不兼容。但是,它与Progressive GPU Lightmapper兼容。
8.1.4 设置Progressive Lightmapper
在Lighting面板中设置其相关属性,如图:

CPU、GPU后端选择,一些其他属性都是在这里设置。具体每个属性的含义,参考"全局光照-Lighting窗口"【链接】。我们可以使用 LightmapEditorSettings 和 Lightmapping API,通过脚本执行此窗口中提供的许多函数。
8.1.5 高级过滤设置
将Filtering属性设置为Advanced,窗口中将会出现一些新的属性,这些属性按光照贴图类型划分,我们可手动配置每种类型的光照贴图的相关属性。类型分为:
-
Direct:直接光。
-
Indirect:间接光。
-
Ambient Occlusion:光照系统计算的任何环境光(环境光)。
属性有:
-
Denoiser:为光照贴图选择一个去噪器(Denoiser)。可选项有:
-
Optix:NVIDIA Optix去噪器是一种AI加速去噪器,可以减少烘烤光图中的噪声。它需要NVIDIA GeForce, Quadro或Tesla GPU,带有Maxwell或新一代架构,使用驱动程序版本R495.89或以上。Optix仅支持Windows操作系统。
-
OpenImageDenoise:英特尔的OpenImageDenoise是一个ai加速的去噪器,可以减少烘烤光图中的噪点。
-
None:不使用去噪器。
-
-
Filter:选择要用于光照贴图目标的过滤器。可选项:
-
Gaussian:选择此选项可将 Gaussian 过滤器用于光照贴图目标。Gaussian 过滤器将双向 Gaussian 过滤器应用于光照贴图。这会使光照贴图模糊并减少可见噪点。
-
A-Trous:选择此选项可将 A-Trous 过滤器用于光照贴图目标。A-Trous 过滤器可以将模糊程度降至最低,同时可以消除光照贴图中的可见噪点。
-
None:不使用过滤器。
-
-
Radius:仅当 Filter 设置为 Gaussian 时,此选项才可用。使用 Radius 值可设置 Gaussian 过滤器内核的半径(以纹素为单位)。较高的 Radius 值可以提高模糊强度并减少可察觉的噪点,但可能导致光照中的细节丢失。
-
Sigma:仅当 Filter 设置为 A-Trous 时,此选项才可用。使用 Sigma 值可调整保留细节或使光照模糊的程度。较高的 Sigma 值可以提高模糊强度并减少可察觉的噪点,但可能导致光照中的细节丢失。
8.1.6 统计信息
Lighting窗口中,在Generate Lighting按钮下方的面板显示了有关光照映射的统计信息,包括:
-
Unity 已创建的光照贴图数量。
-
内存使用量 (Memory Usage):当前光照贴图所需的内存量。
-
占用的纹理像素 (Occupied Texels):在光照贴图 UV 空间中占用的纹理像素数量。
-
融合 (Converged):这些光照贴图的所有计算都已完成。
-
未融合 (Not Converged):这些光照贴图的烘焙仍在进行中。
-
-
烘焙性能 (Bake Performance):每秒的光线数量。如果此值很低(即小于 2),则应调整"设置"或"硬件"以便一次处理更多光线。
8.1.7 ETA
Unity 烘焙光照贴图时出现的进度条提供了"预计到达时间"(显示为 ETA),这是完成当前烘焙的估计时间(秒)。可以让我们快速了解当前光照设置所需的烘焙时间。
8.2 Progressive GPU Lightmapper
Progressive GPU Lightmapper是Progressive Lightmapper的后端,它使用计算机的GPU和Dedicated Video Ram(VRAM)来生成烘焙的光照贴图和光照探针。
8.2.1 硬件和软件要求
为了使用Progressive GPU Lightmapper,计算机需要满足以下最低要求:
-
至少一个支持 OpenCL 1.2 的 GPU。
-
至少2GB的VRAM专用于该GPU。
-
一个支持 SSE4.1 指令的 CPU。
如果我们正在烘焙的场景所需的 VRAM 多于指定 GPU 上可用 VRAM,则烘焙时间会显著增加。有关帮助我们减少烘烤场景所需时间的信息,请参阅下方性能(Performance)。另外,Progressive GPU Lightmapper不支持OpenCL CPU设备。
8.2.2 性能
在大多数配置中,Progressive GPU Lightmapper比Progressive CPU Lightmapper执行得快得多。性能取决于所选择的烘焙配置文件,但是,用于烘焙的GPU规格和专用于该GPU的VRAM数量都会影响我们对lightmapper性能的体验。其他抢夺GPU资源的应用程序也会影响烘焙性能。取决于硬件供应商,减少Unity可用的VRAM数量可能会减慢烘焙过程或导致它失败。
为了获得与Progressive CPU Lightmapper相同质量的结果,Progressive GPU Lightmapper需要多达四倍的间接光采样。Progressive CPU Lightmapper使用一种称为分支路径追踪的方法,它在每次反弹时发射更多的光线。分支路径跟踪方法不适合GPU。
Unity提供了一个电子表格来帮助我们确定Progressive GPU Lightmapper需要多少内存来烘焙我们的场景。有关更多信息,请参阅Progressive GPU Lightmapper Memory Spreadsheet。
8.2.3 防止因光照贴图器tiling引起的烘烤速度减慢
Progressive GPU Lightmapper包含一个称为lightmapper tiling的功能。lightmapper tiling防止Progressive GPU Lightmapper使用所有可用的GPU内存。相反,Unity会在CPU上分配一些临时内存,然后将灯光烘焙进tiles中,tiles的尺寸与GPU可用内存的数量相匹配。Unity根据所选择的烘焙配置文件配置tiling。另外,Progressive CPU Lightmapper没有这种功能。
当tiling功能被激活,同时光照贴图图集分辨率为512px或更大时,烘焙相同的场景,烘焙过程可能比不使用tiling功能的要慢。
8.2.4 特定平台限制
在macOS上,很难确定有多少内存可用。因此,在此平台上更适合退回到CPU,并且按照下面"优化烘焙速度"的说明进行操作是比较合适的。
8.2.5 如何优化烘焙速度
有多种方法可以减少烘焙时间,并避免烘焙超过指定给 GPU 用于烘焙的 VRAM 的情况。
-
关闭其他具有GPU加速的应用程序。GPU加速的2D图像编辑和3D建模软件会使用VRAM,可以关闭图形加速功能或退出这些应用程序。
-
对较小的游戏对象使用光照探针。碎片或小道具等游戏对象会占用光图中的空间,但可能不会对场景的外观产生重大影响。因此,为了优化烘焙速度,可以禁用这些游戏对象的Mesh Renderer的Contribute Global Illumination(实际就修改为非静态了,至少在GI这方面非静态了,如果其他方面有勾选静态那还是静态的),并使用光照探针照亮它们。
-
指定单独的GPU用于渲染和烘焙。如果你的电脑有多个GPU,你可以指定一个用于渲染,一个用于烘焙。请参见下面的配置GPU选择。
-
U使用较少数量的抗锯齿(Anti-aliasing)采样。在Lightmap Parameters Asset(后面会讲,一个设置参数的Asset文件)中这个设置的默认值是8。当你增大这个值时,Unity会使用更多的VRAM。当我们使用4096或更高大的光照贴图时,这可能很快溢出许多消费级GPU的内存。
-
使用更少的采样(直接采样,间接采样,环境采样。这些都是Lighting窗口中的可设置属性),并使用去噪器来清除光图中剩余的噪声。
-
降低光照贴图的分辨率。
8.2.6 配置GPU的选择
如果我们至少有两个GPU,我们可以指定一个GPU用于渲染场景,另一个用于烘焙光照。在默认GPU可用的VRAM不足的情况下,这可能是可取的,我们既可以渲染场景,也可以使用Progressive GPU Lightmapper进行烘焙。
我们需要在Lighting面板中,设置Unity使用哪个GPU进行烘焙:

8.3 光照映射:入门
从Unity Editor菜单中选择Window > Rendering > Lighting打开Lighting窗口。确保你想要应用光照贴图的任何网格都有适当的UVs进行光照映射,最简单的方法是打开Mesh import settings并启用Generate Lightmap UVs设置。接下来,要控制光照贴图的分辨率,请前往 Lighting窗口中的Lightmapping Settings 部分并调整 Lightmap Resolution 值。
想要被包含在光照贴图中(即使用光照贴图功能),渲染器必须满足以下标准:
-
具有 Mesh Renderer 或 Terrain 组件。
-
标记为 Contribute GI(设置为静态了)。
-
使用内置的 Unity 材质、标准着色器 (Standard Shader) 或具有 Meta Pass 的着色器
然后就是烘焙创建光照贴图了(光照映射),就前面全局光照中讲的实时GI、烘焙GI。当执行完成后,Unity的场景和游戏视图会自动更新,同时,Unity 将向Assets文件夹中添加光照数据资源、烘焙光照贴图、反射探针(若用到了),一般是根据场景名创建一个同名文件夹存放内容。
8.4 预览光照映射
我们可以编辑场景并预览光照贴图和光照的变化,而不会影响烘焙的光照映射。
直接看官方文档吧,我用的Unity版本有点低了,没法演示。
8.5 Lightmap Parameters Asset
光照贴图参数资源(Lightmap Parameters Asset)中包含了一组用于控制 Unity 光照功能的参数值。这些资源允许定义和保存不同的光照值集合,以便用于不同的情况。光照贴图参数资源可以用来为不同类型的游戏对象或为不同平台和不同场景类型(例如,室内或室外场景)创建优化的预设。
8.5.1 创建

8.5.2 属性
选中创建的文件,即可在Inspector面板中看到相关属性:

8.5.2.1 Realtime Global Illumination
这些参数用于配置Enlighten Realtime Global Illumination(其光照贴图)。请参render pipeline feature comparison,了解更多关于跨渲染管线支持Enlighten Realtime Global Illumination的信息。(目前下面讲的这个应该是内置渲染管线的)
-
Resolution:此值在Lighting窗口的Scene选项卡中缩放Realtime Resolution(【没找到这个,或者说不太确定这里指的是选项卡中的哪个属性】),以每单位距离的纹理像素来给出光照贴图的最终分辨率。
-
Cluster Resolution:聚类分辨率(内部计算光反射的分辨率)与最终光照贴图分辨率的比率。有关更多信息,请参阅GI Visualizations in the Scene view。
-
Irradiance Budget:此值确定用于照射光照贴图中每个纹理像素的入射光数据的精度。从纹理像素的位置对场景的"视图"采样来获得每个纹理像素的光照。较低的辐照度预算值会导致样本更模糊。值越高,样本的清晰度越高。较高的辐照度预算会改善光照,但这会增大运行时内存使用量并可能增大 CPU 使用率。
-
Irradiance Quality:使用滑动条来定义投射的射线数量,并用于计算哪些聚类影响给定的输出的光照贴图纹理。较高的值可在光照贴图中实现视觉改善,但会增加 Unity Editor 中的预计算时间。该值不会影响运行时性能。
-
Modelling Tolerance:此值控制网格几何体中允许光线通过的间隙的最小大小。降低此值可允许光线穿过环境中更小的间隙。
-
Edge Stitching:如果启用此属性,则表示光照贴图中的 UV 图表应无缝连接在一起,从而避免不必要的视觉瑕疵。
-
Is Transparent:如果启用此属性,在全局光照计算期间,对象显示将为透明。背面不会参与计算,光线将穿过表面。这可用于不可见的发光表面。
-
System Tag:一组对象,它们的光照贴图纹理组合在同一个光照贴图图集内,这组对象称为"系统"。如果无法将所有对象放入单个图集中,Unity Editor 会自动定义其他"系统"及其附带的图集。但是,有时自己定义单独的"系统"会非常有用(例如,不同房间内有多个对象,每个房间单独定义一个系统来划分对象)。更改System Tag的数值可强制创建新的系统和光照贴图。这些数值的序列不重要,即顺序不重要。
8.5.2.2 Baked Global Illimination
这些参数用于配置Lightmapping(光照映射,这里应该说Baked Global Illimination的光照贴图更好理解)。请参render pipeline feature comparison,了解更多关于跨渲染管线支持lightmapping的信息。(目前下面讲的这个应该是内置渲染管线的)
-
Anti-aliasing Samples:(Anti-aliasing可以理解为抗锯齿)。确定采样光照贴图纹理时要使用的子纹理位置的数量。将值设置在1以上,使用超采样来提高光图质量并减少与混叠(aliasing)相关的伪影。
-
值为1禁用超级采样。
-
值为4提供2x2超采样。这是移除大多数混叠伪影的默认值。
-
值为16提供4x4的超采样。使用这些值来去除伪影,比如直接照明下的锯齿状边缘。
-
注意:更高的Anti-aliasing Samples值使用更多的内存。这意味着如果我们在一个大的场景中,并且光照贴图的纹理尺寸较大,这时我们使用一个较大的Anti-aliasing Samples值,光照贴图的烘焙操作可能无法完成。
-
-
Backface Tolerance:texel可能被正面、背面光照。此属性用于选择有多少光量(百分比阈值)来自正面几何体才能将texel视为有效。这使得如果太多光线投射到背面(例如,如果texel在几何体内部),Unity可能会使texel无效。例如,1.0的值意味着当Unity的任何光线击中背面时,Unity认为texel无效(因为要求100%,所以有一个背面的就无效)。当一个纹理无效时,Unity会从周围的纹理克隆有效值来防止伪影。降低此值以解决由背面采样引起的照明问题。可使用Texel Validity Scene View Draw模式来调整此值。
-
Pushoff:根据我们在建模单位中指定的值,沿着法线将光线原点推离几何。Unity将此值应用于所有烘焙的光照贴图。它影响直接光,间接光和烘焙环境遮挡。调整此设置以减少自遮挡和自阴影伪影。
-
Baked Tag:以图集来对对象进行划分。与System Tag一样,数值序列并不重要。Unity永远不会将具有不同烘焙标签值的GameObjects放在同一个图集中。但是,不能保证具有相同标记的对象最终会出现在同一个图集中,因为可能有太多具有相同标记的对象无法放入一个图集中。当我们使用多场景烘焙API时,我们不需要设置这个值,因为Unity在这种情况下会自动分组。我们可以使用Baked Tag来复制Lock Atlas选项的一些行为。请参下面的Baked Tags: Details了解更多信息。
-
Limit Lightmap Count:限制光照贴图数量。勾选此属性后,会出现一个Max Lightmaps属性,决定光照贴图数量的最大值。Unity认为如果游戏对象它们具有相同的Anti-aliasing Samples,Pushoff,Baked Tag和Backface Tolerance,则这些游戏对象具有相同的Baked Global Illumination settings。这意味着Unity可能会将拥有不同Lightmap Parameters Asset的GameObjects打包在一起。为了将游戏对象打包到一定数量的光照贴图中,Unity会按比例缩小UV布局,直到所有物体都符合指定数量的光照贴图,这个过程可能会降低光照贴图的分辨率。
8.5.2.3 Baked Tags: Details

上面的两张图显示了同一场景的两个视图:
-
上图:所有东西都在一个图集中,因为所有的GameObjects都有相同的Baked Tag。
-
下图:其中一个GameObject被分配了一个不同的Baked Tag,则其并被强制放到第二个光照贴图(第二个光照贴图属于另一个图集)中。
-
PS:为什么说Unity官方文档辣鸡,上图还在说图集,下图就变成光照贴图了,说清楚点有那么难?看个文档看得血压上升。
8.5.3 Baked AO
这些参数用于配置烘焙环境遮挡(Baked Ambient Occlusion,Baked AO)。其中,某些参数都来自上面"属性"中。
-
Quality:评估Baked Ambient Occlusion时投射的光线数。较高的射线数增加了AO质量,但也增加了烘焙时间。
-
Anti-aliasing Samples:对AO进行Anti-aliasing(抗锯齿)时需要采集的样本数量。较高的样品数量增加了AO质量,但也增加了烘焙时间。
8.5.4 分配Lightmap Parameters Asset
8.5.4.1 分配给场景
如图在Lighting窗口中设置:

若我们创建了新的Asset文件,在下拉列表中也可以找到。
8.5.4.2 分配给游戏对象
首先需要确保游戏对象已附加网格渲染器 (Mesh Renderer) 或地形 (Terrain) 组件。对于Mesh Renderer的分配:

对于Terrain的分配:

8.6 光照贴图模式
8.6.1 模式
光照贴图有两种模式:Directional、Non-Directional。这两种模式都兼容Unity的Enlighten Realtime Global Illumination系统的实时光照贴图,以及Unity的Progressive Lightmapper的烘焙光照贴图。默认模式为"Directional"。
当我们烘焙Directional光照贴图时,Unity 会生成两个光照贴图纹理。一个纹理存储光照的强度和颜色的信息,此光照穿过目标表面而接收到,这与Non-Directional光照贴图相同。另一个纹理存储主光照方向,以及描述接收到的总光照中来自该主方向的比例。(Directional相比Non-Directional,多了一个光照贴图纹理)
如图,桶烘焙了Non-Directional光照贴图:

如图,桶烘焙了Directional光照贴图:

8.6.2 性能问题
Directional模式光照贴图由两个纹理组成,着色器在渲染过程中对这两个纹理进行采样。额外的纹理增加了对显存需求。生成额外的方向性纹理也会影响烘焙性能。
Non-Directional模式光照贴图仅包含单个纹理。因此,与Directional贴图相比,它们需要的显存和存储空间更少,并且在着色器中解码速度更快。但是,这些优化会降低视觉质量。
8.6.3 设置光照贴图的模式
我们需要在Lighting Settings Asset中进行设置。前面说过怎么设置这个资源文件,这里我们以使用Lighting窗口为例来设置光照贴图模式:

8.6.4 附加场景时的注意点
Unity 可以以附加方式加载场景。这意味着您可以进行多个场景的编辑。若我们使用Directional模式。当我们以附加方式加载场景时,所有场景都必须使用相同的Directional模式,这包括未烘焙的场景,例如 UI 元素或加载屏幕。对于项目中的所有场景使用相同的Lightmap Parameters asset可以帮助我们避免设置冲突。(PS:什么意思?应该是说要模式相同,然后光照贴图的参数也相同吧。)
8.7 环境光遮挡
环境光遮挡 (Ambient occlusion, AO) 功能可以模拟折痕线、小孔和相互靠近的表面中出现的柔和阴影。这些区域将遮挡(阻挡)环境光,因此它们看起来较暗。此功能可以估算环境光照射到表面上某一点的光照强度,然后,使折痕线、小孔和相互靠近的表面变暗。环境光遮挡功能可用于增添光照的真实感。
8.7.1 烘焙环境光遮挡
如果在场景中启用了 Baked Global Illumination,Unity 可以将环境光遮挡烘焙到光照贴图中。这称为烘焙环境光遮挡 (Baked Ambient Occlusion)。要在场景中启用烘焙环境光遮挡,在Lighting面板中勾选相关属性即可,如图:

8.7.2 实时环境光遮挡
如果我们的场景中没有启用Global Illumination,但我们仍然想要环境遮挡的效果,那么我们可以使用一个后期处理效果来应用实时环境遮挡(Realtime ambient occlusion)到我们的场景中。
如果在场景中启用了Enlighten Realtime Global Illumination,则间接照明的分辨率无法捕获精细细节或动态对象。这里建议使用实时环境遮挡后处理效果(即用后处理),它有更多的细节,并产生更高质量的照明。(PS:这里也没说后处理之外的实时环境光遮挡使用方法呀...)
有关实时环境遮挡后处理效果的信息,请参见post-processing effects。
8.7.3 其他资源
想要更详细了解其他内容,请参阅 Wikipedia:环境光遮挡 (Ambient Occlusion)。
8.8 光照贴图:技术信息
Unity 可存储采用不同压缩和编码方案的光照贴图,具体取决于目标平台以及 Lighting 窗口中的压缩设置。
8.8.1 编码方案
Unity 项目可以使用两种技术在必要时将烘焙光源强度范围编码为低动态范围纹理:
-
RGBM 编码。RGBM 编码将颜色存储在 RGB 通道中,将乘数 (M) 存储在 Alpha 通道中。在线性空间中,RGBM 光照贴图的范围是 0 到 34.49(52.2),而在伽马空间中,范围是 0 到 5。
-
双低动态范围 (dLDR) 编码。只需直接将 [0, 2] 范围映射到 [0, 1],即可在移动平台上使用 dLDR 编码。值高于 2 的烘焙光源强度将被钳制。编码值的计算方法是:光照贴图纹理的值乘以 2(如果使用伽马空间),或乘以 4.59482(22.2)(如果使用线性空间)。某些平台将光照贴图存储为 dLDR,这是因为在使用 RGBM 时,这些平台的硬件压缩会产生外观不佳的瑕疵。
使用线性颜色空间时,光照贴图纹理将标记为 sRGB,着色器使用的最终值(采样和解码后)将位于线性颜色空间中。使用伽马颜色空间时,最终值将在伽马颜色空间中。
注意:使用编码时,存储在光照贴图(GPU 纹理内存)中的值始终位于伽马颜色空间中。
UnityCG.cginc着色器 include 文件中的 Decode Lightmap 着色器函数负责在从着色器中的光照贴图纹理读取值之后解码光照贴图值。
8.8.2 HDR光照贴图支持
我们可以在Windows、Mac、Linux、iOS、tvOS和Android上使用HDR光照贴图。要控制这些平台的光照贴图编码/压缩,请转到 Edit > Project Settings > Player > Other Settings > Lightmap Encoding。如图:

选择High Quality将启用HDR光图支持,而Normal Quality将切换到使用RGBM编码,Low Quality将在移动平台上切换到dLDR编码,在其他平台上它相当于Normal Quality。
在桌面平台和游戏主机平台上,Lighting 窗口中启用了光照贴图 Compression 时,将使用 BC6H 压缩格式来压缩光照贴图。对于移动平台,Unity 根据下表选择 HDR 格式。
8.8.3 高质量(BC6H)光照贴图的优点
-
HDR 光照贴图不使用任何编码方案来编码光照贴图值,因此支持的范围仅受到 16 位浮点纹理格式的限制(范围从 0 到 65504)。
-
BC6H 格式质量优于 DXT5 + RGBM 格式编码,并且不会产生 RGBM 编码所具有的任何色带瑕疵。
-
需要对 HDR 光照贴图进行采样的着色器是一些较短的 ALU 指令,因为不需要对采样值进行解码。
-
BC6H 格式与 DXT5 具有相同的 GPU 内存要求。
以下列表列出了每个目标平台的编码方案及其纹理压缩格式:
目标平台 | 编码 | 压缩 - 大小(每像素位数) |
---|---|---|
独立平台(PC、Mac 和 Linux) | RGBM / HDR | DXT5 / BC6H - 8 bpp |
WebGL 1.0 / 2.0 | RGBM | DXT5 - 8 bpp |
iOS ASTC (1) | dLDR / RGBM / HDR | ASTC - 3.56 bpp / ASTC - 3.56 bpp / RGB9E5 - 32 bpp |
iOS PVRTC | dLDR / RGBM / HDR | PVRTC RGB - 4 bpp / ETC2 RGBA - 8 bpp / RGB9E5 - 32 bpp |
tvOS | dLDR / RGBM / HDR | ASTC - 3.56 bpp / ASTC - 3.56 bpp / RGB9E5 - 32 bpp |
Android ASTC (2) | dLDR / RGBM / HDR | ASTC - 3.56 bpp / ASTC - 3.56 bpp / ASTC HDR - 3.56 bpp |
Android ETC2 | dLDR / RGBM / HDR | ETC2 RGB - 4 bpp / ETC2 RGBA - 8 bpp / ASTC HDR - 3.56 bpp |
Android ETC | dLDR / RGBM / HDR | ETC1 RGB - 4 bpp / ETC2 RGBA - 8 bpp / ASTC HDR - 3.56 bpp |
1\] iOS上用于光照贴图的纹理压缩格式取决于[Player Settings](https://docs.unity3d.com/cn/2023.2/Manual/iphone.html "Player Settings")中的纹理压缩格式设置。
\[2\] Android上用于光照贴图的纹理压缩格式取决于[Player Settings](https://docs.unity3d.com/cn/2023.2/Manual/class-PlayerSettingsAndroid.html#Rendering "Player Settings")和 [Build Settings](https://docs.unity3d.com/cn/2023.2/Manual/android-build-settings.html "Build Settings")。有关这些设置如何相互作用的更多细节,请参阅 [Texture compression settings](https://docs.unity3d.com/cn/2023.2/Manual/android-requirements-and-compatibility.html#texture-compression "Texture compression settings")。
#### 8.8.4 预计算实时全局光照 (GI)
GI系统的输入有着不同的范围和编码的输出。表面反照率在伽马空间为8位无符号整数RGB,发射率在线性空间为16位浮点RGB。有关使用meta pass提供自定义输入的建议,请参阅下方面的"光照映射与着色器"小节。
光照强度输出纹理将以 RGB9E5格式存储(如果图形硬件支持此格式),其共享指数浮点,或者以范围在 5 以内的 RGBM 作为后备格式。RGB9E5 光照贴图的范围是 \[0, 65408\]。有关 RGB9E5 格式的详细信息,请参阅 [Khronos.org:EXT_texture_shared_exponent](https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_shared_exponent.txt "Khronos.org:EXT_texture_shared_exponent")。
### 8.9 光照映射与着色器
本节主要讲如何使着色器与Unity的Lightmappers兼容。
#### 8.9.1 The Meta Pass
Meta Pass是一个着色器通道,提供反照率和发射值给Global Illumination系统。这些值与实时渲染中使用的值是分开的,这意味着我们可以使用Meta Pass来控制从光照烘焙系统的角度来看到的游戏对象的外观,而不会影响其运行时的外观(就是说只影响烘焙而不影响实时的。这里所谓烘焙也应该包括实时中的间接光,这点有点不确定,不然实时GI要这个数据也没用啊)。比如,我们想让悬崖上的绿色苔藓在你的光照贴图中产生夸张的绿色间接光,但我们不想在着色器的实时通道中重新给地形上色,就可以使用Meta Pass来控制。
所有Unity的内置材质都有一个Meta Pass,标准着色器包含一个Meta Pass。如果我们使用的就是内置材质、标准着色器,那么我们不需要做任何事情来启用Meta Pass。但如果我们使用自定义着色器,那么我们可以添加自己的Meta Pass。
#### 8.9.2 带有Meta Pass的着色器实例
下面的着色器允许我们指定一个反照率颜色和反照率纹理,只被光照烘焙系统使用,而不影响运行时材质的外观。在这个例子中,发射来自UVs,但任何值都可以用来控制它。
```cs
Shader "Custom/metaPassShader"{
Properties {
_Color ("Color", Color)=(1,1,1,1)
_MainTex ("Albedo (RGB)",2D)="white"{}
_Glossiness ("Smoothness", Range(0,1))=0.5
_Metallic ("Metallic", Range(0,1))=0.0
_GIAlbedoColor ("Color Albedo (GI)", Color)=(1,1,1,1)
_GIAlbedoTex ("Albedo (GI)",2D)="white"{}
}
SubShader {
// ------------------------------------------------------------------
// Extracts information for lightmapping, GI (emission, albedo, ...)
// This pass is not used during regular rendering.
Pass
{
Name "META"
Tags {"LightMode"="Meta"}
Cull Off
CGPROGRAM
#include"UnityStandardMeta.cginc"
sampler2D _GIAlbedoTex;
fixed4 _GIAlbedoColor;
float4 frag_meta2 (v2f_meta i): SV_Target
{
// We're interested in diffuse & specular colors
// and surface roughness to produce final albedo.
FragmentCommonData data = UNITY_SETUP_BRDF_INPUT (i.uv);
UnityMetaInput o;
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, o);
fixed4 c = tex2D (_GIAlbedoTex, i.uv);
o.Albedo = fixed3(c.rgb * _GIAlbedoColor.rgb);
o.Emission = Emission(i.uv.xy);
return UnityMetaFragment(o);
}
#pragma vertex vert_meta
#pragma fragment frag_meta2
#pragma shader_feature _EMISSION
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature ___ _DETAIL_MULX2
ENDCG
}
Tags {"RenderType"="Opaque"}
LOD 200
CGPROGRAM
// Physically-based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows nometa
// Use Shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
void surf (Input IN,inout SurfaceOutputStandard o){
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex)* _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
```
#### 8.9.3 Meta Pass 技术信息
Enlighten Realtime Global Illumination和光照映射(由lightmappers执行映射)使用Unity的Meta Pass从表面提取反照率值,并在每次反弹时使用表面反照率来处理漫反射传输。
具有黑色(或几乎黑色)反照率的金属表面反射很少的光漫反射。Lightmappers只处理漫反射光传输,这意味着我们可能会看到很少的反弹光从这些类型的表面。Unity内置的Meta Pass通过提供增强版的金属色调来实现这种现象(即让我们看不到反弹光),而不是采用物理上正确的反照率。这意味着即使是金属材料,其在Unity中实际也会有反弹。另外,我们可以创建一个自定义Meta Pass,来实现不同的行为。
内置的Meta Pass不处理光谱镜面反射。
注意:如果我使用的是Enlighten Realtime Global Illumination,那么Player中的Meta pass没有DynamicGI.SetEmissive那么快,但它更灵活,因为我们不局限于单一颜色。
#### 8.9.4 自定义RGB透明度
默认情况下,Unity中的着色器使用单色透明度。这意味着Unity使用材质颜色或反照率纹理的alpha通道来评估通过材质的光透过率。
在光照映射过程中,你可以使用自定义RGB透明度,这意味着Unity使用给定纹理的值来评估通过材料的光透过率。当我们想要独立于材料颜色或反照率纹理的基于颜色的透明度时,这是有用的。例如,如果我们想烘焙光照,模拟通过彩色玻璃窗照射的光的行为。
要在光映射期间使用自定义RGB透明度,请在ShaderLab代码中添加以下行:
```cs
_TransparencyLM ("Transmissive Texture", 2D) = "white" {}
```
这将在材质Inspector中创建一个材质属性,名称为"Transmissive Texture"。将所需的纹理分配给该字段。
### 8.10 光照贴图UVs
#### 8.10.1 介绍
Realtime Global Illumination、Baked Global Illumination系统都使用光照贴图,也因此需要光照贴图UVs。Unity在这两个系统中使用单独的光照贴图UVs集合。这有两个原因:
1. 在实时光照贴图和烘焙光照贴图的实例分组中没有直接的对应关系。在相同实时光照贴图中的实例,可能在不同的烘焙光照贴图中,反之亦然。
2. 在烘焙光照贴图中,以不同缩放(scales)出现的网格共享光照贴图UVs,但在实时光照贴图中不共享UVs。
##### 8.10.1.1 Baked lightmap UVs
Baked lightmap UVs(烘焙光照贴图UVs)是per-mesh的:同一网格的所有实例共享相同的Baked lightmap UVs。当我们导入模型时,Unity可以计算Baked lightmap UVs,或者我们可以提供自己的数据。
Unity在网格的[Mesh.uv2](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Mesh-uv2.html "Mesh.uv2")通道中存储baked lightmap UVs,这个通道映射到TEXCOORD1着色器语义,通常被称为"UV1"。
如果启用了Baked Global Illumination,并且给定的MeshRenderer从光照贴图中接收其全局照明,Unity将使用[Mesh.uv2](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Mesh-uv2.html "Mesh.uv2")通道中的数据来正确地把烘焙光照贴图映射到网格。
注意:如果我们想在给定的网格中使用Mesh.uv2用于其他目的,那么必须确保使用该网格的所有MeshRenderer组件都从Light Probes接收全局照明而不是从光照贴图中。可从MeshRenderer组件的Inspector中修改接收设置,也可以使用 [MeshRenderer.receiveGI](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MeshRenderer.receiveGI.html "MeshRenderer.receiveGI") API。
##### 8.10.1.2 Real-time lightmap UVs
Real-time lightmap UVs(实时光照贴图UVs)是per-mesh的:同一网格的所有实例共享相同的输入数据,但不同的Mesh Renderers实例可以在运行时使用不同的real-time lightmap UVs。Unity在预计算阶段计算Realtime Global Illumination系统的UVs。这个计算将per-mesh的UVs作为输入,并使用该数据来创建per-mesh的Renderer UVs。当我们导入模型时,Unity可以生成输入数据:per-mesh的UVs,或者我们可以提供自己的数据。
其工作原理如下:
* Unity可以使用[Mesh.uv3](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/Mesh-uv3.html "Mesh.uv3")通道中的数据作为real-time lightmap UV计算的输入。Mesh.uv3映射到TEXCOORD2着色器语义,通常被称为"UV2"。
* 如果Mesh.uv3中没有数据,但Mesh-uv2中有数据,Unity就会退回到使用Mesh.uv2中的数据作为real-time lightmap UV计算的输入。Mesh.uv2通常用于baked lightmap UVs。使用baked lightmap UVs作为real-time lightmap UVs的输入数据是很常见的。
* 计算结果存储在per-MeshRenderer的[MeshRenderer.enlightenVertexStream](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MeshRenderer-enlightenVertexStream.html "MeshRenderer.enlightenVertexStream")中。如果启用了Realtime Global Illumination,并且给定的MeshRenderer组件Contributes GI(静态设置)并从光照贴图中接收其全局光照,Unity会自动将MeshRenderer.enlightenVertexStream中的数据传递给着色器中的TEXCOORD2,而不是Mesh.uv3中的数据。【什么时候用Mesh.uv3的数据?有点迷惑。这里是说存储行为是一种可选情况吗,若存储了就不适用uv3了?】
注意:如果我们想在一个使用Realtime Global Illumination的网格中使用Mesh.uv3用于其他目的,我们必须确保所有使用该网格的MeshRenderer组件从Light Probes中而不是光照贴图中接收全局光照。可从MeshRenderer组件的Inspector中修改接收设置,也可以使用 [MeshRenderer.receiveGI](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MeshRenderer.receiveGI.html "MeshRenderer.receiveGI") API。(和Baked lightmap UVs那个一样)
##### 8.10.1.3 Unity如何计算real-time lightmap UVs
Unity将per-mesh输入的UVs处理成per-Mesh Renderer输出的UVs时,发生了什么?如下:
**Packing(打包)**
Unity重新打包real-time lightmap UVs去确保每个chart的边界在所有方向上落到一个texel中心,然后在每个chart的边界周围添加half-texel的填充。这确保了所有chart之间有一个完整texel空间。
这是因为real-time lightmaps的分辨率故意设置得很低,以便实时更新它们。低分辨率不会影响图像质量,因为这些光照贴图只存储低频间接光照,但当chart共享texel时,它可能会导致"bleeding"(这种现象在前面有介绍)。重新打包确保chart永远不会共享texel。这种方式不仅避免了这个问题,而且还可以高效地将chart打包在一起。

如图,图中这些网格就是模型网格的展开图,可以理解为我们前面所说的chart(UV chart)。
注意:这种打包技术意味着计算的UVs依赖于实例的scale和光照贴图分辨率,这就是为什么real-time lightmap UVs是per-Mesh Renderer的。但是,Unity会在可能的情况下自动优化这一点:使用具有相同scale和光照贴图分辨率的相同网格的Mesh Renderers会共享相同的UVs。
**Merging(合并)**
或者,我也可以在这个过程中指示Unity合并UV chart。这会减小光照贴图的尺寸,改善运行时内存的使用和性能。
我们可以在任何带有Mesh Renderer组件的游戏对象上启用这个优化。设置位置如图:

注意:这个功能有时会在原始UV映射中,对不连续性产生错误。例如,一个故意锋利的边缘可能会被误解为一个连续的表面。如果发生这种情况,请禁用此功能。
#### 8.10.2 生成光照贴图 UV
当我们导入模型时,Unity可以计算baked lightmaps UVs,或者我们可以提供自己的数据。
##### 8.10.2.1 如何提供自己的光照贴图UVs
我们可以在创建模型的软件中,编写自己的lightmap UVs ,Unity使用这些UVs作为计算的输入。
我们把这些数据放在哪里,取决于我们是为baked lightmaps,real-time lightmaps,或是两者提供UVs:
* 为baked lightmaps提供,我们必须将lightmap UVs放到Mesh.uv2中,这个通道也被称为"UV1"。
* 为real-time lightmaps提供:
* 如果我们已经在网格的Mesh.uv2中存放了baked lightmap UVs,并且想使用相同的UVs作为real-time lightmaps的输入,那么我们不需要做任何事,Unity会退回并共享baked lightmap UVs。
* 如果我们已经在网格的Mesh.uv2中存放了baked lightmap UVs,并且我们想为real-time lightmaps提供不同的UVs作为输入,那么就将real-time lightmap UVs放到Mesh.uv3中,这个通道也被称为"UV2"。
* 如果我们还未在Mesh.uv2中存放baked lightmap UVs,那么我们就要决定为real-time lightmap UVs使用Mesh.uv2还是Mesh.uv3。(就是这两个通道都可以存放的意思)
光照贴图的合理 UV 集应遵循以下规则:
* 应在 \[0,1\] x \[0,1\] UV 空间内。
* 在各个图表之间应有足够宽的边距。有关更多信息,请参阅 [UV 重叠结果](https://docs.unity3d.com/cn/2023.2/Manual/ProgressiveLightmapper-UVOverlap.html "UV 重叠结果")。
* 不得有任何重叠面。
* UV 中的角度与原始几何体中的角度之间差异不大。
* 除非我们希望某些区域具有更高的光照贴图分辨率,否则 UV 中三角形的相对比例与原始几何体中三角形的相对比例之间应该存在较小差异。
##### 8.10.2.2 如何自动生成光照贴图UVs
可以使用 [Model Import Settings](https://docs.unity3d.com/cn/2023.2/Manual/class-FBXImporter.html "Model Import Settings") 告诉 Unity 为模型自动生成光照贴图 UV。
1. 在 Project 视图中选择模型。Unity 将在 Inspector 中打开 Model Import Settings。
2. 在 Model Import Settings 中,导航到 Model 选项卡,然后导航到 Geometry 部分。
3. 勾选 Generate Lightmap UVs 复选框。Lightmap UVs settings 部分显示在 Generate Lightmap UVs 复选框的下方。
4. 可选:配置 Lightmap UVs settings 部分中的设置。
5. 单击 Apply 按钮。Unity 会将光照贴图 UV 生成到 [Mesh.uv2](https://docs.unity3d.com/cn/2023.2/ScriptReference/Mesh-uv2.html "Mesh.uv2") 通道中。
Lightmap UVs settings中的属性:
* Hard Angle:相邻三角形之间的角度(以度为单位),Unity 根据此角度将其视为硬边缘并创建接缝。您可以将角度设置为 0 到 180 之间的值。默认情况下设置为 88 度。如果将此角度设置为 180 度,Unity 会认为所有边缘都是平滑的,这适用于生物模型。默认值(88 度)适用于机械模型。
* Angle Error:UV 角度与源几何体中角度的最大可能偏差(百分比形式,范围从 0 到 100)。默认情况下,此值设置为 8%。
此属性控制 UV 空间中三角形与原始几何体中三角形的差异程度。通常,为避免在应用光照贴图时出现瑕疵,此数值应该相当低。
* Area Error:UV 面积与源几何体中面积的最大可能偏差(百分比形式,范围从 0 到 100)。默认情况下,此值设置为 15%。此属性控制 Unity 保留相对三角形面积的程度。增大此值可以创建更少的图表。但是,增大该值可能会改变三角形的分辨率,因此请确保产生的失真不会降低光照贴图的质量。
* Margin Method:边缘方法。分为两种:Manual、Calculate。
* Manual:手动指定Pack Margin。
* Calculate:基于预期的光照贴图分辨率和对象比例,Unity 计算一个足够大的Pack Margin以避免 UV 重叠。
* Pack Margin:在假设网格占据整个 1024x1024 光照贴图的前提下,相邻图表之间的边距(以像素为单位)。您可以将此值设置为 1 到 64 之间的值。较大的值会增加边距,但也会增加图表所需的空间量。默认设置为 4 像素。此属性仅在将 Margin Method 设置为 Manual 时可见。
* Min Lightmap Resolution:所有场景中使用此网格的 MeshRenderers 的最小光照贴图分辨率(纹理像素/单位)。MeshRenderer 的光照贴图分辨率是以下两个属性的组合:MeshRenderer 的 Scale in Lightmap 属性和其所在场景的[光照设置资源](https://docs.unity3d.com/cn/2023.2/Manual/class-LightingSettings.html "光照设置资源")的 Lightmap Resolution 属性。Unity 使用此信息来计算 Pack Margin。此属性仅在将 Margin Method 设置为 Calculate 时可见。
* Min Object Scale:在所有场景中使用此网格的游戏对象的最小变换比例(transform scale)。Unity 使用此信息来计算 Pack Margin。此属性仅在将 Margin Method 设置为 Calculate 时可见。
##### 8.10.2.3 自动生成光照贴图UVs问题解决
**Pack Margin**
为允许过滤,光照贴图包含图表边缘附近的纹理像素中的光照信息,因此应在图表之间始终包含一定的边距,以免在应用光照贴图时出现光渗(bleeding)。
光照贴图分辨率定义了光照贴图的纹理像素(texel)分辨率。Lightmapper会扩大光照贴图中的一些图表纹理像素以避免黑色边缘,因此网格的 UV 图表必须至少相距两个完整的纹理像素,从而避免光渗。使用 Pack Margin 设置可确保几何体的 UV 图表之间有足够的边距。

在光照贴图 UV 空间中,图表之间的填充需要至少两个完整纹理像素,以免出现 UV 重叠和意外光渗。在此图中,黑色空白表示图表之间的空隙。
**Min Lightmap Resolution and Min Object Scale**
将 UV 图表放置得太近可能会导致在最终的光照贴图中出现[图表纹素交叉渗漏](https://docs.unity3d.com/cn/2023.2/Manual/ProgressiveLightmapper-UVOverlap.html "图表纹素交叉渗漏")。将图表放置得太远会浪费内存。对象的理想打包间距取决于分配给它的光照贴图纹素的数量。
Unity 用于 MeshRenderer 的纹素数量取决于 MeshRenderer 的光照贴图分辨率和变换比例(transform scale)。为了计算合适的边距,Unity 需要知道这些属性的期望最小值。
MeshRenderer 的光照贴图分辨率是以下属性的组合:其所在场景的[光照设置资源](https://docs.unity3d.com/cn/2023.2/Manual/class-LightingSettings.html "光照设置资源")的 Lightmap Resolution 属性和 [MeshRenderer](https://docs.unity3d.com/cn/2023.2/Manual/class-MeshRenderer.html "MeshRenderer") 的 Scale in Lightmap 属性。请注意,这意味着同一个 MeshRenderer 在不同的场景中可以具有不同的光照贴图分辨率。
我们可以使用 Inspector 查看给定场景中 MeshRenderer 的光照贴图分辨率,选中带有MeshRenderer组件的对象:

如图,分别显示了光照贴图分辨率、变换比例。需要注意,Baked Lightmap和Realtime LightMap需要在Lighting面板中执行GI烘焙后才会出现。
**Angle distortion**
以下截屏具有相同的分辨率,但具有不同的 UV。第一张图的 Angle Error 较高,结果中包含意料之外的失真。第二张图使用 Angle Error 默认值 (8%)。在具有较多三角形的网格中,角度失真会让形状显著失真。

**Area distortion**
在下面的图片中,两个具有相同参数的聚光灯照亮圆柱体的侧面。圆柱体的右侧具有较高的Area Error值,这会扭曲三角形并导致较低的分辨率,从而在光线中产生伪影。

#### 8.10.3 可视化光照贴图UVs
能够查看正在使用的光照贴图UVs是很重要的,Unity有一个可视化工具来帮助我们做到这一点。首先打开Lighting面板,然后执行GI烘焙操作,官方文档里建议值勾选自动烘焙选项,确保烘焙、预计算是最新的。
按照官方文档完全找不到可视化方法:[官方文档](https://docs.unity3d.com/6000.0/Documentation/Manual/LightingGiUvs-visualizing.html "官方文档")。不过这种方法可以简单看一看:

#### 8.10.4 解决光照贴图UV重叠
每个光照贴图包含许多的charts。在运行时,Unity将这些charts映射到网格面上,并使用charts的照明数据来计算最终外观。由于GPU采样的工作方式,如果一个chart太靠近另一个chart,它的数据可能会流到另一个chart的数据中。这通常会导致意想不到的问题,如混叠、像素化等。所造成的光渗问题如图:

为避免光渗,chart之间必须有足够的空间。当 GPU 对光照贴图进行采样时,光照系统会从最接近采样点的四个纹理像素计算最终采样值(假设使用双线性过滤)。这四个纹理像素称为采样点的双线性"邻域"。如果chart重叠(也就是说,如果chart中任何点的邻域与另一个图表中任何点的邻域重叠),表示图表太靠近。在下图中,白色像素表示chart邻域,红色像素表示重叠的邻域。

确定最佳图表放置位置和间距可能会很困难,因为它取决于多个参数(例如光照贴图分辨率、网格 UV 和导入器设置)。基于此原因,Unity 提供了轻松识别这些问题的能力,如以下部分所述。
##### 8.10.4.1 识别
有三种方法可识别重叠:
* 密切关注 Unity 的控制台。如果 Unity 检测到重叠的 UV,它会打印一条警告消息,其中包含受影响游戏对象的列表。
* 使用 Scene 视图中的 **UV Overlap** 绘制模式(有关更多信息,请参阅 [Scene 视图中的 GI 可视化](https://docs.unity3d.com/cn/2023.2/Manual/GIVis.html "Scene 视图中的 GI 可视化"))。启用此模式后,Unity 会以红色突出显示chart中的哪些纹理像素过于靠近其他chart中的纹理像素。如果您在 Scene 视图中发现瑕疵,并希望快速检查是否由 UV 重叠导致了此问题,则此方法尤其有用。如图:

从此下拉框中可以选择UV Overlap模式。此模式下若出现UV重叠,则视觉效果如图所示:

* 使用 **Baked Lightmaps Preview** 。选择一个游戏对象,前往 Lighting 窗口,然后选择 **Baked Lightmaps** 选项卡。双击突出显示的光照贴图,导航到 Preview 窗口,然后选择 **Baked UV Overlap**(请查看右上角的下拉选单)。Preview 窗口在此视图中将有问题的纹素标记为红色。如图:

若有重叠,则如图:

##### 8.10.4.2 解决方案
UV 重叠没有唯一的解决方案,因为有很多问题可能导致这种情况。以下是最常见的解决方案:
* 如果由我们自己提供光照贴图 UV,可使用我们自己的modelling package添加边距。
* 如果 Unity 自动为模型生成光照贴图 UV,我们可以让 Unity 增加包边距。最简单的方法是将 Margin Method 设置为 Calculate,并设置适当 Min Lightmap Resolution 和 Min Object Scale。如果愿意将 Margin Method 设置为 Manual,那么可以直接调整 Pack Margin 值。如需了解这些设置的更多信息,请参阅有关[生成光照贴图 UV](https://docs.unity3d.com/cn/2023.2/Manual/LightingGiUvs-GeneratingLightmappingUVs.html "生成光照贴图 UV") 的文档。
* 提高整个光照贴图的分辨率。这样将增加图表之间的像素数量,从而降低发生光渗的可能性。缺点是光照贴图可能会变得太大。我们可以在 Lightmapper Settings 下的 Lighting 选项卡中执行此操作。
* 提高单个游戏对象的分辨率。这种情况下可以仅为具有重叠 UV 的游戏对象提高光照贴图分辨率。这也可能增加光照贴图的大小,但可能性较小。我们可以在它的网格渲染器(Mesh Renderer)的lightmap Settings下改变GameObject的lightmap分辨率。(PS:这里说的应该是使用Scale in Lightmap属性来改变。)

如图,正常,没有发生光渗的情况。
### 8.11 光照贴图接缝缝合
接缝缝合功能可在使用烘焙光照贴图(由渐进光照贴图 (Progressive Lightmapper) 生成)渲染的游戏对象中,平滑不需要的硬边缘。如图,是没有使用接缝缝合功能的情况:

使用后:

当Unity烘焙光照贴图时,它会将靠近但彼此分离的网格面识别为在光图空间中是分离的,这些网格的边缘被称为"接缝"。理想情况下,接缝是看不见的,然而,它们有时会显示为坚硬的边缘。这是因为GPU不能在光照贴图中分开的chart之间混合其纹理像素值。
接缝缝合修复了这个问题。当我们启用接缝拼接时,Unity会进行额外的计算来修改光照贴图以改善每个接缝的外观。拼接并不完美,但它往往大大改善了最终的结果。由于Unity做了额外的计算,接缝拼接在烘焙过程中需要额外的时间,所以Unity默认禁用它。
当我们启用缝线时,lightmapper会识别出应该缝合在一起的边缘对,并在缝线上产生尽可能平滑的照明。这只适用于在图集中沿chart边界水平或垂直走向的直边,其并被设计用于与在UV空间中与轴对齐的矩形一起工作。(PS:这话怎么这么抽象。【】)
#### 8.11.1 接缝缝合的局限性
接缝缝合与[渐进光照贴图 (Progressive Lightmapper)](https://docs.unity3d.com/cn/2023.2/Manual/progressive-lightmapper.html "渐进光照贴图 (Progressive Lightmapper)") 配合使用。接缝缝合仅对单个游戏对象有效;多个游戏对象无法平滑地缝合在一起。
#### 8.11.2 使用接缝缝合
我们可以使用Mesh Renderer组件在任何GameObject上启用接缝拼接。如图:

另外,我们也可以使用 [MeshRenderer.stitchLightmapSeams](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/MeshRenderer-stitchLightmapSeams.html "MeshRenderer.stitchLightmapSeams") API。
### 8.12 自定义衰减
在现实世界中,光线会在远处消失,而且昏暗的光线比明亮的光线具有更低的有效范围。"衰减"一词是指光衰速率。除了 Unity 的默认衰减光照行为外,还可以使用自定义衰减设置。
渐进式光照贴图 (Progressive Lightmapper) 提供自定义衰减预设,我们可以通过脚本来实现这些预设。请参阅表下方的图像以查看这些预设的工作原理的可视化表示,并参阅图像下方的代码示例来了解此功能的用法。
* InverseSquared:应用距离平方倒数法衰减模型。意味着,光照强度与位置到光源的距离的平方成反比减小。有关更多信息,请参阅 Wikipedia:平方反比定律 (Inverse-square law)。此选项在物理上是最准确的。
* InverseSquaredNoRangeAttenuation:应用没有平滑范围衰减的距离平方倒数法衰减模型。这与InverseSquared的工作方式相同,但照明系统不考虑点灯、聚光灯的范围参数的衰减。
* Legacy:应用二次(quadratic)衰减模型。该模型将光衰减基于光源的范围。随着光线远离光源,强度会减弱,但衰减会有非常明显且不自然的下降,视觉效果也不太现实。
* Linear:应用线性衰减模型。在此模型中,衰减与距光源的距离成反比,且衰减以固定的速率从光源开始减弱。

注意:在使用baked或mixed光时,下面的代码示例仅适用于Progressive Lightmapper。要对实时灯光使用如下代码示例,请使用[Enlighten Realtime Global Illumination](https://docs.unity3d.com/6000.0/Documentation/Manual/realtime-gi-using-enlighten.html "Enlighten Realtime Global Illumination")。
```cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.GlobalIllumination;
using UnityEngine.SceneManagement;
[ExecuteInEditMode]
public class ExtractFalloff : MonoBehaviour
{
public void OnEnable()
{
Lightmapping.RequestLightsDelegate testDel = (Light[] requests, Unity.Collections.NativeArray