0%

绝区零场景实现分析(蕾米大厅截帧)

由 astra 生成 · 更新于 2026-09-27 18:44(北京时间)

分析日期:2026-09-27。范围为蕾米所在的室内大厅,输入为本机 leimi_all_resource.rdc。重点是压缩烘焙光、局部灯光、镜像反射、湿润表面和颜色/身份双历史。

本文完整展开本截帧的场景逻辑;角色内部算法见 角色分析。跨游戏结论另见 场景实现对比,回放定位见 证据索引。

本截帧最终画面

总览用于定位场景;算法旁的局部图采用同一区域对照,并写明可观察的变化。阶段配对保持一致显示设置,HDR 预览范围与最终输出颜色分别说明。图片直接从真实回放生成,未修改截帧资源。

1. 管线与数据依赖

阶段 处理逻辑 输出的作用
几何与阴影准备 完成角色变形、翅膀细分,准备阴影代理 可见形状与遮挡形状分别交给对应视图
镜像视图 从镜像视点完成几何、照明、透明与颜色处理 生成主场景使用的平面反射颜色,能包含探针无法直接表示的本场景内容
主材质 输出表面颜色、法线与分类;场景写烘焙光,角色脸部写专用着色结果 形成后续光照的材质输入和已有 HDR 贡献
可见性与光照候选 分级深度用于遮挡判断;屏幕分区/世界网格缩小局部灯光候选;阴影与 AO 生成遮蔽 让后面的像素只处理相关灯光,并区分直接光遮挡与环境遮蔽
补光与合成 按材质类别消费输入,加入局部光、透明、雾和效果 得到当前帧最终待积累的颜色及运动/身份信息
历史与输出 运动定位旧像素,身份与颜色范围控制复用,再处理泛光、运动模糊与最终颜色 稳定当前画面,同时保留高亮的后续处理空间

2. 公共表面数据与材质分类

数据用途 本截帧的生成与编码
表面法线图:保存表面朝向,决定光照与遮蔽 RGB 直接编码方向,RGB10A2
材质颜色图:为后续着色提供表面颜色 RGBA8 sRGB;场景分支保存颜色,部分角色分支改作材质控制数据
HDR 光照颜色图:存放已计算的亮度与颜色 RGBA16F;材质阶段已包含烘焙光/角色着色等结果
运动矢量图:保存前后帧屏幕位移,定位历史像素 脸部已在材质扩展图的 RG 写压缩运动;后续另有运动与像素身份图供时序读取
附加材质参数图:控制表面如何接受后续光照 RGB10A2在场景分支保存材质量、脸部分支复用为运动/标记;另有颜色图 alpha 控制量
材质类别/扩展标记图:选择处理分支 材质图通道与模板分类共同承载
相机深度与模板图:遮挡测试、空间位置重建与分类 D32S8

法线由归一化方向映射为 0.5×N+0.5,消费端用 2×RGB-1 恢复方向。场景材质在写表面数据时建立模板分类,后续光照按类别解释通道:烘焙光照量与角色已着色颜色可以处于同一 HDR 目标,但不是同一种输入语义。

场景材质颜色和脸部控制量也可能复用相同附件;分类必须和通道一起保留。相机、镜像视图与光源的深度分别表示各自可见性,不能彼此替代。

3. 场景材质:压缩烘焙光与湿润表面

材质阶段:已有光照 材质阶段:表面颜色 后续完成后的画面
材质阶段:已有光照 材质阶段:表面颜色 后续完成后的画面

观察 HIA 浮雕字、墙板凹处和吧台面。 左图已经具有明暗,但没有完整表面配色;中图保留红黄标牌、木地板与金属面分区;右图将这些数据与后续着色合成。前两图是同阶段的不同输出,说明光照量与表面颜色的分工;右图还包含后续灯光和后处理,不能当作单一效果开关实验。

以大厅通风口材质为例,其实际绑定包括底色 BC1 sRGB、法线 BC7 UNORM、材质遮罩 BC1 UNORM,以及 4096² BC7 UNORM 的压缩光照/天空遮蔽贴图。材质 UV 与烘焙光照 UV 分开:VS 对第二组 UV 使用每实例的缩放偏移,PS 再按该坐标读烘焙结果。

实例数据并非每 draw 一份独立矩阵。 代表 VS 用 实例编号+起始实例偏移 寻址,每实例跨 11 个 float4。其中位置变换使用前四组,法线使用另一组变换,切线朝向和负缩放符号独立处理,最后一组保存光照 UV 变换。这能说明实例常量的实际步长为 176 bytes;不能由此推出全引擎只有这一种实例格式。

法线采样先从贴图恢复切线空间方向:

1
2
3
4
法线XY = (2×贴图.R×贴图.A-1, 2×贴图.G-1) × 法线强度
法线Z = sqrt(1-min(dot(法线XY,法线XY),1))
世界副切线 = cross(几何法线,世界切线) × 切线符号
着色法线 = normalize(法线X×切线 + 法线Y×副切线 + 法线Z×几何法线)

本帧法线强度为 1。统一使用 R×A 的解包可以兼容不同的法线资源布局,不能因为纹理本次是 BC7 就跳过 alpha。基础材质遮罩的 G 被取反并限制到 0.99 后作为表面响应参数,R 则经独立强度控制;它们还会受到后续湿润处理影响,未把整套遮罩未经消费端证明地统一命名为 ORM。

本次压缩光照分支开关为 1。它把采样值限制到 0.9961,随后做有理式解码:

1
2
3
4
u = min(压缩光照.RGB,0.9961)
烘焙光 = 0.5×u/(1-u)
法线修正 = 0.3 + 0.7×saturate(dot(着色法线,normalize(几何法线)))
光照输出 = 法线修正 × (烘焙光 + 贴图.A×天空颜色) × 光照强度

本帧光照强度为 1,天空附加颜色为零;贴图 alpha 仍经法线修正后保留在 HDR 附件 alpha。这个场景分支将光照量与材质颜色分开写,而角色脸部分支在 HDR 附件写已经着色的颜色;同一 RT0 的读取必须结合材质类别,不能全图统一当成 albedo 或完整最终颜色。

程序还包含空间湿润影响:从世界 xz 位置读湿润噪声,结合环境高度图的四次比较采样与位置高度范围,得到允许受影响的程度;表面朝上程度参与抑制竖直面。湿润量进一步改变颜色、表面响应参数,并在强度超过一定范围时把切线法线往 (0,0,1) 拉回,即压低细节起伏。仅从材质贴图本身看不出这些由世界环境控制的变化。

四个输出中,sRGB 颜色附件 alpha 打包三个布尔位;法线附件 alpha 固定为 0;材质扩展附件 alpha 在 0.67 与 1.01 间选取,写入 2-bit UNORM 后对应约 2/3 与 1。它是分类值而非透明度,解读时必须考虑附件量化。

证据:场景顶点程序、场景材质程序、本帧场景常量、本帧材质常量。

4. 局部灯光候选与列表构建

屏幕路径先计算灯光包围范围,选出与当前屏幕分区重叠的光,再按深度层和格子几何继续筛选。世界网格路径则按空间位置建立另一套灯光列表。两者都把“遍历全部灯光”变成“只读取当前格子的候选”,但寻址空间和表头布局不同,见下面的布局与筛选步骤。

局部灯光列表解决直接光的候选查找;烘焙光照贴图、天空遮蔽与环境反射探针提供另外的贡献。它们在同一场景中并存,不能把全部环境亮度归给屏幕空间计算。

屏幕分区、深度层与压缩表头

继续读取计算程序和本帧常量后,可以明确屏幕灯光组织的实际粒度:

项目 本帧数值 / 布局 实现意义
屏幕分区 64×64 像素 3432×1440 向上取整得到 54×23 个分区;最右/最下区域会裁到实际画面边界
每组线程 64 第一阶段分担灯光候选检查,后续每线程可对应一个深度层
深度层数 64 由本帧指数参数 6 得到 1<<6
每个屏幕分区的候选容量 128 共享内存中的候选数组有硬上限;超出的候选不会被该数组保留
灯光记录步长 156 bytes 包含类型和用于相交测试的数据;不是只有位置/半径的 float4
空间包围数据步长 16 bytes 分别读取屏幕范围与深度范围,先做粗筛
表头 每类每格 32 bits 高 5 bits 存数量,低 27 bits 存列表起始偏移;写入数量限制到 31
两类灯光索引 分别以对应类型的起始位置为基数 列表保存类型内相对索引,消费端必须先还原所属类型,再读取灯光记录

处理流程不是一次原子追加就结束:

  1. 每个线程每轮检查一盏光,按 64 的步幅遍历输入列表;屏幕包围范围与当前 64×64 区域重叠才加入候选。
  2. 使用组内原子计数压紧候选,将候选数截到 128,补齐到 2 的幂并用 bitonic 排序网络按索引排序。排序保持后续类型/索引组织有序,不是按光照贡献大小挑选。
  3. 把每盏候选光的起止深度映射到层号;一盏灯光的两个 8-bit 层号占 16 bits,两个灯光范围可以放进一个 32-bit 共享记录。
  4. 按深度层计数并为全局索引列表预留空间,然后继续做灯光体积与格子几何的相交测试。
  5. 输出类型相对索引,并分别写两类的“数量+偏移”表头。消费者必须使用对应类型基数还原灯光索引。

深度层不是均匀间隔。本帧参数为近端 0.03、远端 5000、几何比 1.1,层边界可提炼为:

1
2
3
层边界(k) = 近端 + (远端-近端) * (1.1^k - 1) / (1.1^64 - 1)
层号(z) = clamp(floor(log_1.1(1 + max(z-近端,0)/(远端-近端)
* (1.1^64-1))), 0, 63)

这些数值控制的是本次构建的深度划分,单位遵从捕获引擎,不能直接当成相机 UI 显示的米数。近处层更密,远处更稀,可在固定层数下覆盖很大的深度区间。

世界网格灯光路径有另一套结构:36-byte 的网格描述、360-byte 的灯光记录、8×8 线程组;组内通过 1/2/4/8/16/32 步长的前缀和计算输出偏移,再由一个线程向全局列表分配整组空间。它的格子表头采用高 8 bits 计数、低位偏移的组合,而非屏幕列表的高 5 bits 计数。两者的 buffer/表头格式不能共用一个未经区分的解码器。

证据:屏幕灯光列表构建、本帧屏幕列表参数、世界网格灯光筛选。

5. 阴影缓存、屏幕解析与局部遮蔽

局部光阴影按子区块放入图集,主相机相关的阴影视图则存入数组。阴影代理可以使用不同于可见材质的几何;角色脸部还消费附加阴影深度,处理主场景阴影之外的遮挡需求。

屏幕解析先由相机深度恢复可见表面位置,再投影到对应阴影视图进行比较,将“光源能否看见这里”转换成当前像素的受光比例,随后滤波。对象级分类和解析接在公共结果上,使局部角色遮挡可以拥有独立规则;具体接入见 角色阴影与胶囊遮蔽。

屏幕环境遮蔽具有独立的生成和过滤链,半分辨率 R8 遮蔽历史参与后续消费;分级深度为屏幕查询提供输入。角色胶囊路径还使用简化空间几何,和只沿可见深度搜索的屏幕遮蔽分开。

当前已确认它们的输入输出与接入顺序,未完整还原屏幕 AO 的方向采样规则与每个历史权重,不能仅凭程序名称指定某个库版本。

6. 平面反射与环境探针

平面反射从镜像视点重新处理场景几何、材质、照明、透明与颜色后处理,生成主视图使用的离屏颜色。它有自己的深度与可见性,因此反射数据的生产本身是一条场景渲染路径。

镜像视图生成的大厅反射

场景同时使用压缩 HDR 立方体反射探针。镜像视图与环境探针是不同来源:前者依赖额外视点的几何与着色结果,后者以预存空间方向颜色参与反射。两种来源在各材质中的完整选择和混合规则尚未全部拆解。

7. 天空、雾与分域颜色变换

天空查找表为环境颜色计算提供预计算数据;角色、场景与通用颜色变换又各有查找表。因此角色在进入最终整帧合成之前,就可以采用不同于场景的颜色变换,眼睛路径的具体查表公式见 角色眼睛分析。

雾的可见链路包含生成屏幕颜色与合成。当前证据还未把其内部介质存储完整还原,不能将它直接套成另外两者已确认的三维体积积分方法。

8. 时序融合:颜色与像素身份共同验证历史

运动图的 RG 保存压缩屏幕位移,B 保存历史身份标记,附加覆盖标记控制部分采样和旁路。颜色历史采用 HDR RGB,身份历史独立保存在 R8。身份用于重投影匹配,尚未证明它等同于 CPU 逻辑对象编号。

1
2
3
4
q = 编码运动.RG - 127/255
运动v = sign(q) × (2q)²
历史UV = 当前UV - v
历史权重 = 0.95 - 0.25 × saturate(5000 × length(v))

完整处理有以下先后关系:

  1. 从中心和四个对角深度候选中择近,沿该表面的运动寻找历史;中心覆盖标记和标记的屏幕导数影响是否去除当前采样偏移,以及是否旁路历史。
  2. 点采样历史身份,与当前身份比较。差值绝对值大于 0.1 时直接输出当前颜色及身份,停止使用旧颜色。
  3. 身份允许时,对旧 HDR 颜色取双线性样本;当前颜色读取中心和四个半 texel 对角位置,本帧使用 0.6 的锐化参数。
  4. 按最大颜色通道把 RGB 压入较小范围;用对角邻居的最小/最大值与亮度差构造扩张区间,沿区间中心方向裁剪旧颜色。
  5. 按运动量把历史基础权重从约 0.95 降至约 0.70,混合后反变换;最后由中心标记进一步混向当前颜色。
  6. 同步输出新 HDR 颜色和当前身份,作为下一次历史。

因此身份拒绝处理的是“是否仍对应当前表面”,颜色裁剪处理的是“旧值是否仍适合当前邻域”,运动权重处理的是“积累应有多强”。三者不能互相代替。

证据:时序融合程序、同截帧时序公式核对。

9. 泛光、运动模糊与最终输出

主要历史融合在最终颜色处理之前完成,后面继续泛光、过滤与运动模糊。角色/场景专用颜色查找表可以更早参与材质着色,因此最终颜色变换不是全部调色逻辑的唯一位置。

10. 分析边界与证据

烘焙光、灯光列表、部分场景材质、镜像视图与主要时序规则已有直接证据。全部局部灯光消费分支、屏幕 AO 内核、雾内部存储、其他场景材质变体与跨帧缓存更新策略仍未完整还原。

场景绑定附录 保留原始管线状态,资源语义索引 对照各资源用途;各算法段落的程序与常量链接可用于重新核对。