"Hello, everyone. My name is Sergey Makeev, and I'm a Senior Technical Director at Roblox. Today I'll talk about scaling user-generated 3D worlds: why rendering on Roblox is a hard problem and how we approached it. I'll give you some context about the platform, show you a demo, and then dig into how it all works."
- 先抹掉常规假设:Roblox 是平台,涵盖引擎、云服务、内容系统与社区;一个渲染器要接住没有单一美术方向、没有固定内容预算、没有已知硬件目标的用户生成内容(讲义 slide 2)。世界由服务端持有的活数据模型驱动,「静态」只是假设(讲义 slide 3)。
- 三根支柱:资产转码器保留稳定版本化的源、按需派生运行时形态(讲义 slide 10–26);SLIM(Scalable Lightweight Interactive Models)世界转码器把同一套契约用到世界的选定区域(讲义 slide 29–44);运行时编排让每个客户端在两份固定预算上挑细节(讲义 slide 45–48)。
- 一句话结论:发布冻结的是源,不冻结优化。编码器或 LOD 算法变好,二十年老内容在下一次请求里自动升级,创作者不必重做(讲义 slide 26)。
- 收益读数要带口径:实例 −97%、三角形 −98%、draw call −74%、显存 −33% 是同一场景、同一相机的引擎内实时抓帧,绑定单个 kitbash 演示场景,不可外推(讲义 slide 48)。
- 诚实的边界:结构频繁变动、一次性唯一几何、严格低延迟、过度聚合四类场景收益锐减;未来工作按讲者原话是研究方向,不是已发布功能(讲义 slide 60、62)。
1先把常规假设抹掉:Roblox 的平台前提
先把常规假设抹掉:Roblox 的平台前提
开篇先把讲台立稳。讲者自报姓名与职位:Sergey Makeev,Roblox 的高级技术总监(Senior Technical Director)。这场讲的是用户生成三维世界的规模化渲染,两件事并排:为什么在 Roblox 上做渲染是件难事,以及他们怎么应对(讲义 slide 0)。随后他放了一段混剪多个 Roblox 游戏的视频,并请观众记住一条:视频里每个游戏都跑在同一份引擎上,同一版代码与内容必须在他们支持的全部设备上都跑得好,这个跨度是 Roblox 渲染难做的很大一块(讲义 slide 1)。
接下来讲者给 Roblox 划界。单一游戏、单一虚拟世界、可以对外授权的引擎,这三个说法都不足以概括它;Roblox 指的是平台本身,由引擎、云服务、内容系统,以及建立其上的创作者与玩家社区组成(讲义 slide 2)。视频里看到的一切都是用户生成的:创作者做世界、化身、服装与工具,平台负责把它们投递到主机、PC、手机、平板、VR 头显,甚至智能电视。对一个渲染工程师来说,这份定位抹掉了平时赖以立足的三条假设,没有单一美术方向、没有固定内容预算、没有已知硬件目标,渲染器只能去接住创作者接下来做的任何东西。
世界的心脏是数据模型(data model)。它是一棵活的对象树:对象、属性、脚本,以及对资产的引用;讲者给的类比是三维世界里的 HTML DOM(讲义 slide 3)。游戏服务端持有仿真并持续更新这棵树,脚本与物理随时能改动任何东西,每个客户端只收到它需要的那部分。他们自家的编辑器 Roblox Studio 用的是同一套数据模型与同一份引擎代码,上面再叠协作式多人编辑。这件事的分量在于:在 Roblox 上,「静态」只是假设,从来不是保证,凡依赖离线优化或一次性烘焙的常规手法都被排除在外;一个典型的 Roblox 世界一直在变,从不到达稳定态。
把镜头换到内容投递这一侧(讲义 slide 4)。创作者点一下「发布」,新版本立刻在所有设备可用;玩家不装 build、不等补丁,加入一个 Roblox 游戏更接近打开一个网页。玩家进来时,服务端开始复制这份活的数据模型,网格、纹理与音频另从 CDN 到达,而这一切发生的同时世界还在变:仿真在跑,资产随玩家走动流进流出。这里同样没有稳态,也没有一个可以说「世界到此定稿」的时刻。
体量把上面两条前提压得更实(讲义 slide 5)。每天创作者上传约 120 万块网格与 160 万张图片;随便哪一天,约 26% 的头部 1000 款游戏会推一版更新,直达数以百万计的玩家。这些内容都得跨八个平台跑通,而高端设备的算力约是低端设备的 800 倍。二十年积攒下来的内容超过 700 PB,其中很多还要跑在它诞生时并不存在的设备上。于是也没有「内容完工」这一步:新内容不断进来,老内容必须继续能用,硬件目标一直在动。
这一页的读数需要口径限定。120 万网格/日、160 万图片/日、约 800 倍算力跨度、26% 头部游戏更新、20 年 700+ PB 全部是讲者所述的平台级指标,页内表体由幻灯片位图 OCR 读出(讲义 slide 5(OCR)),既无论文也无受控实验,不可复现,也不能当作某个可搬走的基准数。
讲者在开场视频里特意请观众带着一个前提去看:视频里每个游戏都跑在同一份引擎上,同一版代码与同一批内容要在他们支持的全部设备上跑得好。这条约束贯穿全篇,也解释了后面为什么要把优化推迟到运行时:没有哪一次提前的、面向某个目标的决定能一直有效,因为目标本身由创作者与玩家随时改写。
把 p2 到 p5 连起来,本章能核对的结论有三条。Roblox 作为平台,把美术方向、内容预算、硬件目标这三条假设一并交给创作者随机决定(讲义 slide 2)。世界由服务端持有的活数据模型驱动,「静态」不成立,凡依赖离线烘焙的手法都被排除(讲义 slide 3、4)。体量一侧的读数是每天约 120 万网格与 160 万图片上传、八个平台、约 800 倍算力跨度、20 年 700+ PB,均属讲者所述平台级指标(讲义 slide 5(OCR))。下一章把这份体量落进一个具体场景,看一帧要花多少三角形。
2一帧 5940 万三角形的 UGC 世界与三根支柱
上一章把体量摆在前台,这一章把它落进一个具体场景(讲义 slide 6)。讲者先自嘲:他是图形工程师,不是美术,但这个演示是按很多创作者的做法搭出来的,从目录里拿几千个资产做 kitbash。它带着这类场景该有的性质:三角形与纹理密度不均、小物件成堆、重叠几何很多。单个资产各自都没问题,可几十万个凑在一起就成了一个低效场景。这个场景大约有 17.2 万个数据模型实例;朴素渲染一帧是 5940 万个三角形与约 3500 次 draw call。讲者给的判词很直:这贵到连桌面都渲不动,而它必须跑在一台 100 美元的手机上。
这一页的精确读数同样要标口径:172,531 实例与 3,526 draw call 来自幻灯区位图的 OCR 读出,讲者备注里对应的是约 17.2 万与约 3500(讲义 slide 6(OCR))。两组数说的是同一件事,正文以备注的约数为陈述口径,精确数只作 OCR 补充,不合并成第三个数字。这个场景的构成方式也须记牢:它是单人用目录资产拼出来的 kitbash 场景,后文所有百分比读数都绑定它。
然后就是结果(讲义 slide 7、8)。桌面上一段 4K 的实时视频,用的是他们称为 SLIM 的优化表示;换到手机上放同一场景,数据模型相同、资产相同、引擎相同,没有单独的移动版,唯一的差别是运行时表示(runtime representation)。这一段把整篇的账当场兑了一次:同一个世界,两种表示,两类设备。讲者在这一页没有报新数字,桌面 4K 与手机两段视频的作用是让观众先看到结论,再回头看它是由什么换来的。
数字在讲义 slide 9 一页上给全。朴素渲染这个场景每帧要约 5900 万个三角形;用上 SLIM 后,桌面降到 470 万,平板 240 万,手机只要 110 万。这一组读数出自幻灯区表体,为 OCR 读出,讲者备注给的对应值是约 5900 万、470 万、240 万、110 万(讲义 slide 9(OCR))。讲者随即给出三根支柱。第一,资产转码器(asset transcoders):把创作者内容保留为稳定、带版本的源数据,需要什么运行时形态就派生什么。第二,SLIM 世界转码器:同一套概念,从一块资产推广到整片世界。第三,运行时编排(runtime orchestration):每个客户端在自己的内存、渲染与网络预算里挑最合适的那一档细节。
把三根支柱与三档读数并排看,能得到这一章的落点。转码器负责按稳定源派生出更轻的形态,世界转码器把这件事从单块资产放大到整片区域,运行时编排负责在每台设备上按预算挑一档。三者分工清楚,也解释了讲者为什么把 SLIM 这个缩写放在演示视频那一页:它在这里指整条流水线的名字,涵盖资产转码、世界转码与运行时编排三处。至于每台设备具体怎么省下三角形、省到什么程度,要等第 10 章把两个预算摆出来才说得清。
本章可核对的结论有三条。演示场景是单人用目录资产拼出的 kitbash 场景,约 17.2 万实例、朴素 5940 万三角形、约 3500 draw call(讲义 slide 6(OCR))。同一场景在桌面 4K 与手机上实时跑通,数据模型、资产、引擎都相同,差别只在运行时表示(讲义 slide 7、8)。SLIM 把每帧三角形降到桌面 470 万、平板 240 万、手机 110 万(讲义 slide 9(OCR)),支撑它的三根支柱分别是资产转码器、SLIM 世界转码器与运行时编排。下一章展开第一根。
3可变世界里的稳定输入:内容平台取代离线 cook
上一章把三根支柱的名字立起来,这一章展开第一根(讲义 slide 10)。分隔页把资产转码器的想法压成一句话:保留源,派生运行时形态。为什么需要它,p11 给了动机:Roblox 世界从不安静下来,实例来来去去,脚本改属性,物理挪东西,这不是边角情形而是常态;他们没法把世界冻住再跑离线构建或烘焙。讲者在此处补了一句限定,世界一直在变,并不等于所有东西一直在变,后面这句限定会变成整套机制的地基。
接下去是这块地基本身(讲义 slide 12)。活的数据模型可变,它引用的资产不可变。一条资产引用指向唯一一个精确且不可变的版本:确定的纹理字节、确定的网格数据。创作者编辑资产时,系统生成一个新版本,旧版本底下的字节永远不会被改动。于是世界尽管一直在变,资产引用仍然提供稳定的输入,后面所有机制都站在这上面。
稳定归稳定,固定格式这件事并不成立(讲义 slide 13)。资产被创建的时候,谁也不知道它将来会被什么设备取用;压缩格式随平台而变,编码器一直在改进,新平台不断加入,他们自家的格式在内容发布很久之后还在演进。一套永久编码无法服务所有设备。他们也不要求创作者重发老内容,既有内容必须自动前向兼容,这件事听上去最初几乎做不到。
答案在 Roblox 的内容平台(content platform)(讲义 slide 14)。讲者走了一遍取件请求:客户端从数据模型里取一条资产引用,发出资产 ID、精确版本,以及一份它认识的格式清单。这个例子请求的是一张纹理,先 BC1,再 ETC2,最后回到原始源。次序有意义,第一项是首选,其余是兜底。内容平台把这份 ID、版本与格式解析成真正的内容字节。
命中是最省的一条路(讲义 slide 15)。所要形态已经存在,平台回一个 CDN URL,客户端直接下载,什么都不用重建,问同一件事的每个客户端拿到同一个结果。未命中的路要长一些(讲义 slide 16):创作者当初只传了源,运行时格式是派生出来的;想要的表示不在,平台就提交一个转码任务,任务进队列,转码器取走,抓来那个精确的源版本处理,这个例子里是生成 mipmap 并压缩纹理,结果作为该资产的一个新表示发布。此后它就是缓存内容,后续请求一律复用。这段工作是异步的,所以未命中这条路还需要一条安全的回退。
客户端不会等转码跑完(讲义 slide 17)。首选格式缺失就试清单里的下一个;优先级更低但已经就绪的格式先用着,首选同时继续在云里生成;一个都没就绪,服务端回一句「没准备好,稍后再试」,客户端就照做。讲者在这里点出关键:回退属于内容契约的一部分,它让新格式可以出现而不必卡住游戏。讲义 slide 18 把整幅图景收拢,传统的资产 cook 没有凭空消失,它挪进了内容平台内部,对用户不可见、按需运行;一份稳定的源产出任意多的运行时形态,每个结果都被缓存、被共享。
这份契约的力气在于它把「新格式上线」与「游戏能不能跑」解耦了。首选格式还在云端排队时,客户端已经用兜底格式把画面撑起来;一个都没就绪也只是收到一句稍后重试,并不构成会话的中断。讲者把这条路径称为安全的,安全指的是它不会因为格式演进而掐断正在进行的游戏。
本章可核对的结论有三条。资产引用指向唯一确定且不可变的版本,这是整条链路的地基(讲义 slide 12)。取件请求由资产 ID、精确版本与有序格式清单三件组成,首位优先、其余兜底(讲义 slide 14)。未命中时平台入队转码任务、抓精确源版本、产出新表示并落缓存,客户端不等转码,回退属于内容契约(讲义 slide 15、16、17)。下一章给这些派生形态起名字,并把系统的生产量级摆出来。
4生产量级与 ACR:两条版本轴
上一章讲清取件的两条路,这一章把系统的名字与量级补齐。讲义 slide 19 先说那幅图被简化过,真实系统还管审核、权限、本地化、负载均衡等一大堆事。然后是量级:在生产规模上,它每秒服务约 1200 万次请求;转码器机队有 960 台服务器,合计约 16.8 万 GHz 的 CPU 算力与 8.3 TB 内存。这三个读数都是讲者所述的平台级指标,页内表体由位图 OCR 读出(讲义 slide 19(OCR)),无论文与受控实验,不可复现,也不代表某个可搬走的基准。
派生的形态到这里有了正式名字(讲义 slide 20)。每个派生形态称为一个替代内容表示(alternative content representation),缩写 ACR。一个资产 ID 下挂着多个不可变的源版本,每个源版本产出许多 ACR:纹理编码、网格 LOD、遮挡数据等等。这里要记住两条互相独立的版本轴,创作者编辑资产,得到一个新的源版本(source version);转码器代码变化,从同一个源得到一个新的 ACR 格式版本(ACR format version)。ACR 走内容寻址、被缓存、被去重;源是永久的,每一个 ACR 都可弃,因为系统随时能重新生成它。
由此多出一条很有用的性质(讲义 slide 21):新旧引擎版本可以共存,即便资产格式变了。每个引擎版本只请求它认识的格式,平台从同一个源服务不同的 ACR,没有全局转换也没有协同升级;当老客户端不再请求某个旧格式,平台直接回收它。再往下是执行位置的自由(讲义 slide 22):同一份输入无论在哪里跑都产出同一份结果,于是执行地点变成一个部署选择。在云里,转码器产出的结果与数百万玩家共享;同一份转码器也能跑在 Studio 或客户端上,生成即时的本地预览;还能跑在游戏服务端,处理游戏局内现场生成的内容。决定放在哪里的是延迟、算力、复用与信任,代码本身不决定这件事。
两个真实例子把这条自由落到画面上(讲义 slide 23)。上面那段视频是 Cube4D,他们那个在运行中的游戏里生成内容的生成式 AI 模型:玩家描述一个物件,模型在游戏会话里直接产出网格、纹理与脚本;这种情况下转码发生在游戏服务端,结果可以只服务本局、可以发布到平台、也可以被玩家否掉丢弃。右边那段视频是 Roblox 妆面,玩家直接编辑的一层分层纹理,它会触发两个转码任务:一个本地任务给即时的、只有该玩家可见的预览,一个云端任务做安全检查、更好的压缩与跨游戏共享。两处走的是同一份契约,工作只是跑在需要它的地方。
这套机制能长期跑下去,靠的是 p21 与 p22 给出的两条性质。旧格式的退场是被动的,平台等老客户端不再请求它才回收,无需一次全局切换;执行位置的选择是主动的,云端、编辑器、游戏服务端三处跑同一份代码,把结果留在需要它的地方。两条性质都建立在同一个前提上:处理是确定性的,输入是稳定且带版本的。
本章可核对的结论有三条。ACR 是派生形态的正式名字,一个资产 ID 挂多个源版本、每个源版本产出多个 ACR,源永久而 ACR 可弃(讲义 slide 20)。生产量级为每秒约 1200 万请求、960 台转码器、约 16.8 万 GHz 算力与 8.3 TB 内存,全部是讲者所述平台级指标(讲义 slide 19(OCR))。同一份输入无论在哪跑都产出同一份结果,执行位置成为部署选择,决定它的是延迟、算力、复用与信任(讲义 slide 21、22、23)。下一章把两条管线的演进史摆出来,看这套机制如何吃到二十年的老内容。
5纹理与网格的两条时间线:发布冻结的是源
上一章给派生形态起了名字,这一章用两条时间线证明这套机制的收益落在哪里。先看纹理(讲义 slide 24)。早期每个客户端下载 PNG、解码、生成 mipmap,再在运行时建一张未压缩的 RGBA 纹理;能用,但每个客户端都要付这份成本。约 2013 年他们开始用一台临时凑的云端纹理转换器产出 GPU 原生、块压缩的纹理,那台转换器只处理纹理、只支持少数几种硬编码格式。2019 年上了 PBR 材质,几层纹理必须一起处理,因为生成 mipmap 时法线贴图会影响粗糙度,这一步把他们推进了转码器时代。有了转码器,2025 年他们把纹理拆成多个 ACR,可以从 CDN 渐进流式拉取,同年还上线了率失真优化(rate-distortion optimization),明显压低了纹理下载体积。今天转码器用现代编码器产出 KTX2 纹理,并支持渐进式纹理流。而源从未变过:二十年前上传的一张纹理,这些改进全都自动拿到。
网格走了一条相似的路,中段还绕了个小弯(讲义 slide 25)。2016 年起用的是简单的文本格式,每个客户端在加载时解析这些文本文件。2017 年他们开始在导入阶段生成二进制文件,这是上传前的客户端处理步骤。到 2021 年,导入还支持换肤网格并自动生成 LOD,但这些处理都发生在上传之前,实际上改写了源资产的定义。问题在这里冒出来:每做一次改进就多出一种网格格式,因为老网格改不动;峰值时引擎同时支持十种不同的网格格式,包括最初那套文本格式。LOD 也吃了同一个亏,它只在导入时生成一次,后来更好的算法与修好的 bug 都惠及不到既有资产。转到转码器之后就不一样了:他们上线 Draco 压缩压低下载体积,又把最新的网格简化器接进转码器,于是每一块既有网格都拿到了更好的 LOD,没人需要重传任何东西;现在他们还在上面叠渐进式网格流。
讲义 slide 26 给出这段历史的结论:发布冻结的是源,不冻结优化。每当他们做出更好的编码器或更好的 LOD 算法,老内容在下一次请求里就拿到全部改进;他们改善二十年的内容,不请任何人重做。这套东西跑在很大的规模上:每分钟约产出 2.7 万个纹理 ACR 与 2.4 万个网格 ACR,每小时有超过 1.36 亿个 ACR 从 CDN 取用。这三个读数是讲者所述的平台级指标,页内表体由位图 OCR 读出(讲义 slide 26(OCR)),不可复现。同一页还给出资产转码器的一条硬上限:它一次只看得见一块资产;一个由数百万块各自最优的资产组成的世界,渲染起来仍然太贵。
这段历史里有一处代价讲者没有回避:早期每个客户端都要自己解 PNG、生成 mipmap、建未压缩纹理,这份成本在每一台设备上重复支付;等到处理搬到云端,客户端只剩下载与使用。二十年的老内容之所以能一路跟进,靠的是源与派生形态被彻底分开,这处分开在下一章会被推得更远,从一块资产推到整片世界。
本章可核对的结论有三条。纹理与网格的管线各自演进,每一次改进都曾多出新格式,峰值时引擎同时支持十种网格格式(讲义 slide 24、25)。转码器时代让老内容随下一次请求自动拿到编码器与 LOD 算法的改进,源始终不变(讲义 slide 26)。吞吐读数为每分钟约 2.7 万纹理 ACR 与 2.4 万网格 ACR、每小时超过 1.36 亿次 ACR 取用,均属讲者所述平台级指标(讲义 slide 26(OCR));而资产转码器一次只见一块资产,这条硬上限把问题推到整片世界上。
6从一块资产到整片世界:SLIM 与描述符
上一章收在资产转码器的硬上限上,这一章把优化单元放大(讲义 slide 27,本页另有 [time check 21:00] 标记)。p28 把理由说得很平实:Roblox 世界由许多小的、可复用的部件搭成。一块立方体可能已经是最优的,一百万块就不是。资产转码器只看单块网格,它不知道这些立方体组成了这栋楼,看不见它们的相对重要性、看不见它们的尺度、也看不见夹在它们之间的隐藏表面。只有看整幅构图,那些优化才成为可能:合并几何与材质、去掉隐藏表面、为聚合体建 LOD。于是结论落在一句话上,优化单元必须长大,从一块资产长到整片世界。
这也是第二根支柱的定位(讲义 slide 29)。讲者说转码契约从来就不是真为资产而设:它要的是一份稳定、带版本的输入与确定性的处理,产出的是内容寻址、可缓存、可复用的结果,资产只是第一个工作负载。SLIM 是 Scalable Lightweight Interactive Models 的缩写,它把同一套机具用到一片活世界的选定区域上。源数据模型保持权威且可编辑;世界转码器取这片区域的一个渲染视图,派生出更轻的运行时形态;客户端像用任何别的 ACR 一样用它们。在此之前还有一步,把活的可变数据模型翻成一份稳定的转码输入。
那份输入就是 SLIM 描述符(SLIM descriptor)(讲义 slide 30)。它由服务端创建,因为服务端持有完整的数据模型、看得见整片世界。今天的具体做法是:创作者把数据模型里的一棵子树标记为可 SLIM 化;自动边界选择仍在推进中,他们在探索自动分段等思路。描述符只存转码器做渲染需要的东西,几何与材质引用、变换、颜色。资产负载留在描述符外面,描述符只带引用,从不带真正的字节。活世界变化时,服务端更新描述符,客户端消费派生的 SLIM 输出。这里还附了一条好性质:客户端不再需要为了渲染而持有整份数据模型,它的数据模型视图可以明显缩小,省内存、提性能、降网络带宽。
把 p28 到 p30 三页连起来,能看出这套设计的两条边界。一条是空间的边界,SLIM 作用在世界里被选定的区域,并非一次算完整个世界;另一条是内容的边界,描述符只装渲染需要的引用与变换,资产字节留在外面,由既有的资产转码链路独立供给。两条边界把 SLIM 与「把整片场景烘成一个大静态模型」这类做法区分开,也解释了它为何能用「选定区域」四个字来限定作用范围。
本章可核对的结论有三条。优化单元必须从一块资产长大到整片世界,因为单块资产的最优凑不成整片场景的最优(讲义 slide 28)。转码契约要的是稳定版本化输入、确定性处理与内容寻址复用,SLIM 把同一套机具用到活世界的选定区域,源数据模型保持权威可编辑(讲义 slide 29)。SLIM 描述符由服务端创建,只存几何与材质引用、变换与颜色,只带引用不带字节;自动边界选择仍在推进中,当前靠创作者手动标记子树(讲义 slide 30)。下一章讲这份描述符怎么拿到一个稳定的身份。
7内容寻址与归一化后哈希
上一章讲描述符怎么被造出来,这一章讲它怎么拿到一个稳定的身份(讲义 slide 31)。普通的资产有资产 ID 与版本;SLIM 描述符从不被显式发布,所以它没有 ID。代替方案是让内容本身定义身份:对描述符的字节做哈希,这个哈希就是地址。如果哈希已经存在,就复用这份描述符以及由它派生的一切;如果是新的,服务端上传一次,此后平台负责转码并缓存结果。内容寻址的好处在描述符被上传之前就显现:重复内容在提交阶段就被认出来,于是同一个模型可以跨不同的游戏会话复用,甚至跨不同创作者做的不同游戏复用。
这里有一个必须守住的前提(讲义 slide 32):屏幕上看起来一样的模型,必须产出逐字节相同的描述符,否则整套去重机制就会散架。这就是他们先归一化、再哈希的原因。两个模型可以用差别很大的数据模型子树来表示同一个物件:子节点顺序不同、实例命名不同、变换里带着浮点噪声。直接对原始数据做哈希,每一种差异都会变成一个不同的身份。于是他们剥掉所有对渲染没有影响的东西:把属于运行时参数的状态因子化出来(变换、颜色、材质),量化浮点,把实例与属性排成规范次序,其余一律丢弃。归一化之后,等价模型产出相同的字节与相同的哈希,这个哈希就成为地址。
讲义 slide 33 用那台 van 把这套流程从头走了一遍。服务端取来活数据模型的子树,抽出渲染状态,归一化结构,因子化出参数,去掉一切不影响画面的东西;归一化后的字节给出 SLIM 地址。别处一台等价的 van,名字、变换、来历都不同,也会解析到同一个地址。到此他们把一个活世界里的局部变成了稳定、可复用的输入,接下来该让它变成可渲染的东西。哈希地址的示例前缀由讲义 slide 32 的幻灯区位图给出(讲义 slide 32(OCR)),须人工过图核对字符。
归一化这一步还解释了这套设计为什么敢把地址交给内容本身。资产之所以能有 ID 与版本,是因为有人在上层替它记账;SLIM 描述符随时由数据模型重算,没有这样一层登记,只能让内容自己给出身份。剥掉子树顺序、命名与浮点噪声之后留下的,是真正决定画面的那些字段;只要这些字段一致,两个模型的地址就一致,去重与复用随之成立,不依赖任何外部台账。
用那台 van 能看清去重的实际落点:同一台 van 在不同玩家的世界里各自被摆过、被改名过、被脚本挪过,只要归一化后剩下的渲染字段一致,它们就收敛到同一个地址,平台只转码一次。讲者把这一步称为内容寻址在上传前就抓住重复,它的直接后果是跨游戏复用,间接后果是内容平台不必为每个副本各存一份派生形态。
本章可核对的结论有三条。SLIM 描述符没有显式 ID,身份由描述符字节的哈希充当地址,内容寻址在上传前就抓到重复,可跨会话与跨游戏复用(讲义 slide 31)。去重的前提是等价模型产出逐字节相同的描述符,因此要先剥离子树顺序、命名与浮点噪声,量化浮点并规范排序(讲义 slide 32)。van 的流程是提取渲染状态、归一化、因子化参数、去掉与画面无关的内容,再由字节得到 SLIM 地址,别处的等价 van 解析到同一地址(讲义 slide 33)。下一章跟着这台 van 走进世界转码器。
8世界转码器:烘焙变换、按材质聚合、去内部面
上一章把一片活世界翻成了稳定、可复用的输入,这一章看世界转码器把它变成可渲染的形态(讲义 slide 34)。它做的事分几步:把每个部件翻成模型空间里的可渲染几何;按兼容的材质与 shader 状态给几何分组,合并成更大的块;去掉藏在内部的表面;为聚合体建起若干级细节。每一级都记下自己的字节数与几何误差。产出的是一组多档 SLIM ACR,一档对应一个保真度级别。转码器不面向任何具体设备;到了运行时,每台设备按相机视锥、屏幕尺寸,以及自己的性能与内存预算去挑一档。同一页还给出远近三档的具体做法:近处逐材质用原始贴图渲染,远处把材质合成一个运行时材质、把小尺寸贴图打进纹理数组,于是整台 van 一次 draw call 画完,更远则用纯色替掉贴图。这台 van 上,60 块源网格合成 1 个几何块,13 份源材质合成 1 个运行时材质。
讲义 slide 35 到 p40 是那六步图,讲者逐页把 van 推过整条流水线。描述符那一步已经讲过,要点是它始终很小:变换、颜色、资产引用,从不带负载,这让每一个输入都是显式且可复现的。接着是取资产数据(讲义 slide 36)。讲义 slide 37 特意点出一件事:世界转码器是沙盒化的游戏引擎代码,并非为每一种 Roblox 格式另写一套实现,它跑的是与运行时相同的代码。这段代码校验描述符,遍历实例,收集去重后的资产 ID,再把每一个解析到精确的源版本;它先查共享的本地磁盘缓存,缺的从 CDN 取,可能是源资产也可能是某个资产 ACR,然后全部装进内存。描述符很小,可它依赖的每一项都精确而显式。
再往下是搭聚合体(讲义 slide 38、39)。第一步把每个部件的位置、旋转、缩放烘进一份共享的模型空间,这一步涂掉了原本的物体边界,让网格简化器可以跨整幅构图工作。随后按兼容的材质与 shader 状态分组、合并,只有在平台上限逼着时才开新批,例如撞到 16 位索引缓冲上限。这里还有一句必须记住的限定:聚合并不等于把一切都变成静态。对骨骼网格,他们把输入骨架合并成一份共享骨架,保留蒙皮权重与骨骼影响;对静态网格,他们给每块输入网格加一根虚拟骨。所以聚合之后依然能转动一个轮子或打开一扇门。讲者的经验法则是,优化结构,同时保住它与活数据模型之间的映射。
讲义 slide 40 起是去掉永远不进画面的几何。转码器为整个聚合体建一棵 BVH,因为转码期间要做很多次可见性测试(讲义 slide 41)。对聚合体里的每个三角形,他们沿它的面积撒采样点,大三角形拿到更多采样点;从每个采样点朝几个方向射射线,看有没有哪条能逃到开阔空间。规则刻意保守:只要有一条射线逃出去,这个三角形就可能被看见,留下;只有在所有采样都找不到出路时才删掉它。这样能清掉内部与重叠的三角形,又不会在模型上开出可见的洞。
本章可核对的结论有四条。世界转码器把部件翻成模型空间几何、按材质与 shader 状态分组合并、去内部面、为聚合体建多级 LOD,产出多档 SLIM ACR,转码器本身不面向具体设备(讲义 slide 34)。van 上 60 块源网格合成 1 个几何块、13 份源材质合成 1 个运行时材质,近处逐材质、远处合成运行时材质并把小图打进纹理数组,做到一次 draw call(讲义 slide 34)。转码器是与运行时同码的沙盒化引擎代码,先查本地磁盘缓存、缺的从 CDN 取,再全部装入内存(讲义 slide 37)。聚合保留对活数据模型的映射,骨骼合并、静态网格各配一根虚拟骨;去内部面用 BVH 加面积布点射线,任一射线逃出即保留(讲义 slide 39、41)。下一章讲剩下的简化与打包。
9自研网格简化与多档 ACR 打包
上一章把几何聚成一个整体并清掉了内部面,这一章收尾,讲简化与打包(讲义 slide 42)。讲者先用那台 van 给出两级细节的读数:最细的一级约 9,200 个顶点、8,400 个三角形;到第四级降到约 2,600 个顶点、1,600 个三角形。这两个读数是这一个模型的,换一个模型数字会变,引用时须带上模型。
讲义 slide 43 讲简化算法本身。他们得自己写一个,因为用户生成的内容很少给干净的流形拓扑。这个算法显式地存下顶点、边、面之间的关系,不使用传统的半边(half-edge)数据结构;它处理一条边带一个、两个或多个相邻面的情形,并且让本来断开的部分保持断开。二次误差度量(quadric error metric)负责保住原始表面,他们又加了一项面积损失的罚项来改善结果;尖锐折痕以及 UV 或其他顶点属性上的畸变,都会抬高一条边被折叠的代价。每一步简化折叠当前代价最低且有效的边,解出新顶点位置,只更新附近的候选;在属性缝处,他们保留多份属性值而不焊接成一份。结果是拿到一组可用的细节层级,而不要求干净拓扑,因为干净拓扑很少出现。讲者在此页给出一篇论文出处(Liu, Zhang & Yuksel 2025 的《Simplifying Textured Triangle Meshes in the Wild》),该出处由幻灯区位图 OCR 读出(讲义 slide 43(OCR));它是算法的方法来源,不是代码许可,讨论算法细节须回引论文。
把简化器接进转码器之后,它的收益方式与第 5 章那条网格时间线一致:算法换一版、参数调一次,既有内容不必重传,下一次请求就用上新结果。简化器输出的一组细节层级,再由讲义 slide 44 的打包步骤配上误差与字节价签。讲义 slide 44 是最后一步,把各细节层级打包成多个 SLIM ACR。每一档装着可渲染的数据,顶点、索引、纹理 ID 与材质映射;再附上运行时在档位之间做选择所需的元数据:几何误差、三角形数、字节数。到这里,世界转码器的输出全部就位,客户端拿到的是一排明码标价的档位。
两级读数也说明了档位之间差在哪里。最细一级承载近处要看的形状,第四级把它压到约四分之一上下的三角形量,留给远处;中间还隔着若干档,供运行时按屏幕覆盖去挑。打包时附上的三项元数据各有分工:几何误差用于与理想档比较,三角形数用于对齐渲染预算,字节数用于在内存池里排序。缺了任何一项,第 10 章那套按「每字节消除的可见误差」打分的规则都跑不起来。
本章可核对的结论有三条。van 的最细一级约 9,200 顶点、8,400 三角形,第四级约 2,600 顶点、1,600 三角形,读数是这一个模型的(讲义 slide 42)。简化算法为 UGC 而写,不用半边结构,显式存点边面关系,QEM 加面积损失罚项,折痕与属性缝抬高折叠代价,属性缝处保留多份值;方法出处为 Liu, Zhang & Yuksel 2025(讲义 slide 43(OCR))。打包后每档 SLIM ACR 带顶点、索引、纹理 ID、材质映射,以及几何误差、三角形数、字节数三项选择元数据(讲义 slide 44)。下一章换到第三根支柱,看客户端怎么花预算。
10运行时编排:两个预算与一笔率失真的账
上一章把档位与它的标价准备好了,这一章进入第三根支柱(讲义 slide 45):运行时编排。转码器造出了保真度档位,接下来由每个客户端决定怎么在自己几份预算上花钱。
讲义 slide 46 把客户端要解的问题拆成两个相连的部分,性能与内存。性能预算管的是每个可见实例能拿到多少细节:可见性与屏幕覆盖定义出理想 LOD,当场景贵到渲不动时,渲染预算把目标往下拉;超过理想档的细节买不到任何东西,因为这个物体根本没盖住足够的像素去显示它。内存预算管的是哪些 LOD 能常驻显存:所有 SLIM 网格共用一份固定的字节预算,每份共享网格只存一份,用不上的档被逐出,缺失但有用的档来竞争剩下的内存。讲者把两句总结并排放:性能决定哪些细节有用,内存决定哪些细节留得住。两者合起来,就定下整个场景能达到的最好可见画质。
讲义 slide 47 把这套说法落到数上。设备能力与画质设置定下两份固定预算。渲染预算是三角形目标,桌面 470 万、平板 240 万、手机 110 万;内存预算是一池固定的 GPU 字节。场景复杂度改变的是这些预算的竞争,预算本身不动。每一帧,可见性与屏幕覆盖给出每个实例的理想 LOD,渲染预算给出实际目标。内存这一侧,他们先逐出高过新目标的档,再对每个有用但缺失的档按其「每加一字节消除的可见误差」打分,把能塞进剩余内存的最高分升级载进来。讲者说这套做法有个熟悉的学名,率失真优化(rate-distortion optimization),把字节花在能消除最多可见误差的地方;同页给出启发出处(Shoham & Gersho 1988,OCR)。
讲义 slide 48 回到那个演示。这张表比较同一场景、同一相机下的几台设备,一列一台。相对朴素基线,他们砍掉最多 97% 的客户端实例、98% 的三角形、74% 的 draw call,GPU 内存降 33%。讲者强调:表里每个数都来自同一个源世界,反映的是不同设备与不同预算;桌面、平板、手机都没有手工版本,一切都是按需生成,每台设备挑自己能做到的最好表示。
这组百分比必须带足限定。它是同一场景、同一相机下的引擎内实时抓帧(讲义 slide 48 原话 Same scene and camera, real-time engine capture),基线是「朴素渲染不作任何优化」这一极端口径,读数的对象是这个 kitbash 演示场景,因此它既不可外推为通用收益,也不能读成相对既有 LOD 或合批方案的增量收益。三档设备的数分别标在各自的列里,百分比由幻灯区位图 OCR 读出(讲义 slide 48(OCR))。
本章可核对的结论有三条。客户端每帧解两个相连的问题,性能预算决定哪些细节有用、内存预算决定哪些细节留得住(讲义 slide 46)。两份预算是固定的,渲染预算为桌面 470 万、平板 240 万、手机 110 万的三角形目标,内存预算为一池 GPU 字节;升级按「每加一字节消除的可见误差」打分,即率失真(讲义 slide 47)。相对朴素基线,同一场景同一相机下砍掉最多 97% 实例、98% 三角形、74% draw call,显存降 33%,不可外推(讲义 slide 48(OCR))。下一章看这三档设备各自长什么样,以及世界动起来后怎么办。
11同一个世界的三档设备,与动态 SLIM
上一章给出那张表的骨架,这一章把三档设备一档一档看过去,再进到世界动起来的部分(讲义 slide 49 起)。p49 是朴素基线,每帧 5940 万个三角形。p50 是开着 SLIM 的桌面,画面近乎一样,却只用 470 万个三角形,同场景、同相机;讲者让两幅图来回切换,评语是差异看得见但很小,他们去掉的那些工作对最终画面几乎没有影响。p51 是调试视图:没上色的物体走常规渲染路径,颜色标示每个物体被选中的 SLIM 细节档。这里有一处要留意,选出来的档不构成简单的距离环,近处物体在屏占小或几何误差小时反而拿到更低的档,远处物体可以拿到更高的档,尤其当一份常驻网格同时服务许多可见实例时。可见性、屏幕覆盖、复用、三角形成本、字节成本与全局预算,全都汇进编排器。p49 到 p51 这几页只有画面与备注文字,没有对应插图。
p52 与 p53 是平板,目标 240 万。运行时会优先去掉视觉损失最小的细节,于是场景在约为桌面一半的预算下仍保住轮廓与密度;调试视图里选档更激进,更多物体走 SLIM,但决策仍是全局按价值做的,他们没有扳动某个大的画质开关,每一份常驻档位都还在按「每字节带来的可见收益」竞争。p54 与 p55 是手机,目标 110 万。讲者如实交代,他从未把这个演示做成面向移动端的,手机上他只为截这张图跑过一次;优化形态由平台自动派生,手机挑了自己塞得下的那一档。这一句把定位说清了:手机那条读数是一次性截图的产物,不是一轮移动端调优的结果。
到 p56 为止画面看起来基本是静态的,可 Roblox 世界会动、会演、会变,于是有了动态 SLIM。讲义 slide 57 给出切分方式:服务端持有活的数据模型,实例、属性、变换、颜色、动画状态,以及驱动它们的脚本;客户端持有一份不可变的 SLIM 制品,里面有聚合几何、细节档、材质映射与参数槽。前文往聚合体里插的虚拟骨,以及它与数据模型之间的映射,在这里派上用场:它们让一份不可变的制品能对变换与颜色变化作出反应。服务端对这些参数做紧凑快照并复制给客户端,渲染器把它们施加到 SLIM 模型上;几何全烘在一个聚合体里、一次 draw call 画完,而颜色仍在变、轮子仍在转。
讲义 slide 58 讲网络这一侧的预算。既然 SLIM 制品里已经装好结构与映射,他们就不必把每条属性更新发给每个客户端。客户端本地已经握有仿真状态的,直接拿来给 SLIM 模型配参数,网络开销为零;客户端没有的模型,服务端才需要复制状态,做法是按重要度排队,并把更新节流在一份固定的网络带宽预算之内。他们还会记录距上次更新过了多久,免得远处的模型永远冻在同一个姿势里;近处的模型更新更频繁,但最终每个 SLIM 模型都会拿到更新。投递刻意做成不可靠,且很简单:没有重传队列,也没有确认,因为一份更新的快照会让所有旧快照作废。在接收端,快照是稀疏到达的,客户端用五次惯性化(quintic inertialization)把它们抹平,把稀疏的网络包还原成平滑的渲染帧率运动;这一处受到 David Bollo 在 GDC 2018 的启发(OCR)。讲义 slide 59 另给一个例子,1,200 个活的动画化身,服务端全程保持权威,客户端只画轻量制品、接收那些屏幕上真正要紧的运动快照。
本章可核对的结论有四条。三档设备看的是同一场景同一相机,桌面 470 万、平板 240 万、手机 110 万,桌面与朴素基线近同画面(讲义 slide 49、50)。调试视图显示选档不构成简单距离环,可见性、屏占、复用、三角形与字节成本、全局预算共同决定档位,平板与手机的选档更激进而决策仍按价值(讲义 slide 51、52、53)。手机那条读数为一次性截图,讲者自陈只为截图跑过一次(讲义 slide 54)。动态 SLIM 把服务端的可变数据模型与客户端的不可变制品分开,靠参数快照与虚拟骨驱动;网络投递不可靠、无重传无确认,客户端用五次惯性化抹平稀疏快照(讲义 slide 57、58、59)。下一章收边界与反例。
12边界与反例:SLIM 在哪些地方不划算
整篇讲到这里,剩下的是一份诚实的边界清单(讲义 slide 60)。讲者说 SLIM 在优化聚合体上极其有效,随后自己把话说清:它在何处还能改进,在何处不适合用。
讲义 slide 60 列出四类不划算的场景。结构频繁变动会不断造出新描述符,把系统淹没在重复任务里,这种情形下他们更愿意回退到传统渲染。只用一次的唯一几何仍能从 LOD 与流式加载里得到好处,可去重几乎给不了什么,内存成本涨得很快,可能把用量顶出预算;为了留在限额内,编排器被迫逐出高分辨率档,画质明显掉一截。延迟是个硬问题,即便快照本身没错,对高度动态的仿真也可能到得太晚。聚合本身也有代价,大而稀疏的模型让视锥剔除与遮挡剔除都变得没那么有效。讲者把契约写明:在结构稳定、可复用、这笔交易划算的地方用 SLIM,不划算就回退,回退是让优化保持正确的机制。
讲义 slide 61 收出四条经验:保住真源、派生表示,源始终权威、优化形态可弃,算法变好只需重新转码;带上下文与显式契约去优化,归一化、自动发现复用、只在假设成立时聚合,把回退当成契约的一部分;让运行时预算决定细节层级,转码器造选项、客户端把预算花在能买到最多可见画质处;把不可变结构与活状态分开,几何与参数槽放进制品,服务端快照负责让一切继续运动。
讲义 slide 62 列出讲者想推进的方向:更好的 SLIM(更丰富的参数化与部分失效、点云与高斯泼溅与 impostor 这类三角形之外的远处表示、以及「SLIM 由 SLIM 组成」的层级化空间 SLIM);完全分布式的渲染引擎(渲染任务跑在客户端、游戏服务端、机架或云端,同一契约产出可缓存复用的结果,例如为全局光照生成一个 ACR);内容上采样(转码器也能增强,几何、纹理、材质、光照、动画都可借生成式 AI 变好);以及 Roblox Reality 这一混合渲染架构(AI 世界模型需要持久化的空间与语义记忆,可设想一个 SLIM ACR 存放视觉模型输出、或以潜空间表示世界)。讲者把这些界定为研究方向,并说明它们不是已经发布的功能(research directions, not shipping features)。
边界 1:平台级读数全部是讲者所述的平台级指标。 1200 万请求/秒、960 台转码器、约 16.8 万 GHz、8.3 TB RAM、每天约 120 万网格、20 年 700+ PB、每分钟约 2.7 万与 2.4 万 ACR、每小时超过 1.36 亿次取用(讲义 slide 5、19、26),无受控实验、不可复现,页内表体由 OCR 读出。
边界 2:收益读数是同一场景同一相机的引擎内实时抓帧,不可外推。 实例 −97%、三角形 −98%、draw call −74%、显存 −33%(讲义 slide 48)的基线为朴素无优化口径,绑定单个 kitbash 演示场景,不能读成相对既有 LOD 或合批方案的增量收益。
边界 3:不与任何商用方案横比。 SLIM 依赖 Roblox 的数据模型、内容平台、ACR 内容寻址缓存与 CDN,脱离这套基础设施收益无法直接迁移;讲者自陈手机只跑过一次、且只为截图(讲义 slide 54)。
边界 4:讲义 slide 62 的未来工作是研究方向。 四项按原话 research directions, not shipping features 引用,不得写成已落地;讲义 slide 30 的自动边界选择同为 work in progress,当前靠手动标记子树。
边界 5:讲义 slide 43 只给算法论文出处,不是代码许可。 Liu, Zhang & Yuksel 2025 是方法来源(OCR),全篇无 MIT、open source 或 GitHub;版面与 21 件插图页脚为 All Rights Reserved、无 CC 声明,故按非 CC 口径逐件署名并标残留风险。
边界 6:幻灯区无文本层,页内读数全部来自 OCR。 讲义 slide 5、6(172,531 与 3,526)、9、19、26、32、43、47、48 的页内数字一律标「讲义 slide N(OCR)」,须人工过图复核;备注里的约数与 OCR 精确数不合并。
本章可核对的结论有两条。四类不划算场景是结构频繁失效、一次性唯一几何、严格低延迟与过度聚合(讲义 slide 60);平台级读数与收益读数各带各的口径限定,讲义 slide 62 的未来工作按研究方向口径引用,讲义 slide 43 只给论文出处而非代码许可。
13贡献块
三条贡献与站内互读
一场生产向的讲座能留下什么,取决于它把哪些东西讲到了别人抄得走的程度。SLIM 这一篇留下的三样都带明确的依赖前提:一套把离线 cook 搬进云端的资产转码流水线,一份把优化单元从资产放大到世界的做法,以及一层按预算挑选的运行时编排。它还有一条贯穿全篇的口径纪律,平台级读数与单一演示场景的收益读数分列,正文凡出场即带限定,因此这三样贡献都只报「怎么做的」,不替读者把收益外推。
贡献 1:一条把离线 cook 搬进云端的资产转码流水线。 源永远不可变且带版本,运行时形态按需派生、内容寻址、可缓存可去重;ACR 与两条版本轴(源版本、ACR 格式版本)把「新格式上线」与「游戏能不能跑」解耦,老客户端不再请求旧格式时平台直接回收(第 3 到第 5 章,讲义 slide 12/20/26)。想在自己管线里做到「发布冻结源、不冻结优化」的读者,这套契约可以借鉴,前提是自己先有一层内容寻址缓存与按需转码的机队。
贡献 2:把优化单元从一块资产放大到整片世界。 SLIM 描述符只带引用不带字节、归一化后哈希做跨会话跨游戏去重;世界转码器烘焙变换、按材质聚合、用 BVH 加面积布点射线去内部面、建多级 LOD,并把结果按保真度打成多档 ACR(第 6 到第 9 章,讲义 slide 30/32/34/41/43)。这条路径可搬的是思路与契约,不是它的规模读数,也不是那台 van 的具体数值。
贡献 3:一层按预算挑选的运行时编排。 渲染预算是三角形目标、内存预算是一池 GPU 字节,升级按「每加一字节消除的可见误差」打分;动态 SLIM 再把不可变结构与活状态分开,靠参数快照与虚拟骨让制品动起来,网络投递刻意做成不可靠并用五次惯性化抹平稀疏快照(第 10、11 章,讲义 slide 47/57/58)。四个百分比读数只对那个演示场景与那台相机成立(讲义 slide 48)。
站内可以接着读的几篇:同一届 SIGGRAPH 2026 Advances(Part II)的篇目 29(Smolder)与本篇同为生产向讲座,前者讲体积效果怎么变成引擎里的通用系统,与本篇「把预算花在看得见的地方」是同一种取舍;篇目 30(Adaptive Tessellation and Subdivision)把细分搬到 compute 上做自适应,理由是 2D 每级只剩 1/8、3D 只剩 1/16,与本篇「按预算选档」在预算思路上互相呼应;篇目 23(变率光追)、篇目 26(PSSR 升级)、篇目 27(ORCA)也在同一批里,可作生产视角的对照。本篇讲义全篇没有给出代码仓库或开源链接,唯一的算法出处是讲义 slide 43 的论文(Liu, Zhang & Yuksel 2025)。
14原文出处块
原文出处与引用口径
出处:SIGGRAPH 2026 · Advances in Real-Time Rendering in Games(Part II)· 讲者 Sergey Makeev(Senior Technical Director, Roblox)· 官方讲义《SLIM: Scaling User-Generated 3D Worlds on Roblox》,64 页,612×792 pt(信纸竖版),来源 PDF 2026-siggraph-advances-slim.pdf
材料:官方讲义 64 页,每页带讲者备注(口播脚本,有文本层);幻灯区无文本层,页内标题与数字由位图 OCR 读出,须人工过图复核;本篇事实、读数与页码取自讲者备注与选页台账;页码为 PDF 页序(从 0 起),引用写作「讲义 slide N」
许可:逐页页脚 © 2026 SIGGRAPH Advances in Real-Time Rendering in Games course. All Rights Reserved.(右侧并带 ROBLOX 字标),全篇无 Creative Commons 声明,亦无代码许可(无 MIT / open source / GitHub);讲义 slide 43 只给出算法论文出处(Liu, Zhang & Yuksel 2025),不是代码许可。故 21 件图按分区非 CC 口径逐件署名(源 slide 号 + 出处 + 版权行 + 「未修改引用」),并在构建记录标注残留风险,不得写成 CC 或可自由转载
引用口径:平台级读数(12M req/s、960 台转码器、168K CPU GHz、8.3 TB RAM、1.2M 网格/日、700+ PB、27K/24K ACR/分、136M+/h)一律标「讲者所述平台级指标」,无受控实验、不可复现;收益读数(实例 −97%、三角形 −98%、draw call −74%、显存 −33%)为同一场景、同一相机的引擎内实时抓帧,不可外推,且不与任何商用方案横比;讲义 slide 62 的四项未来工作按讲者原话(research directions, not shipping features)作研究方向引用,不得写成已落地;幻灯区页内读数一律标「讲义 slide N(OCR)」