CD Code Digest Hub /GTA V

特效、布料、绳索、破碎与植被

本文分析专门化模拟与视觉系统如何连接物理、动画、场景和渲染;基于源码静态研究,未编译或运行。入口:Summary。

12 分钟阅读 8 个章节 1 张图

1. 专门系统的价值:缩小问题,而不是统一求解所有现象#

RAGE 没有把布料、玻璃、刚体碎片、粒子和草地塞进一个通用模拟器。它们对精度、生命周期和可见性的要求不同:布料需要保持形状和人物附着;碎片需要改变刚体拓扑;粒子需要大量短生命周期实例;草地需要在相机附近重建视觉密度。这些系统共享任务、资源、物理查询和绘制机制,但保留自己的数据表示和预算。

这是系统间共通模式,非声称每个模块具有完全同名的阶段接口。

2. 布料与绳索:位置约束、数据排列与显示网格解耦#

2.1 求解对象是顶点和边#

phVerletCloth 保存顶点及边约束;clothController 连接它与可绘制资源、pinning 和 LOD。UpdateEdgesVec3V 读取边的两个顶点、静止长度平方、压缩权重和端点权重,将约束误差按权重分摊回顶点位置。这里直接修正位置,不是给每个网格顶点建立独立通用刚体。

代码将 1 - sqrt(restLength² / length²) 近似为 1 - 2*restLength²/(length²+restLength²) 并夹到 [-1,1],减少开方成本并限制单次修正。其收益是计算量可控;分析上,代价是大形变下近似误差、约束迭代数和稳定性耦合。不能把这种位置约束实现等同于现代 XPBD:本次没有发现足以证明使用 compliance 和跨迭代拉格朗日乘子更新的证据。

UpdateEdgesSoAVec3VBy8s 将八条边组织为 SoA 批次并预取下一批边数据,配合 vector 类型减少寄存器压力和隐藏访存延迟。源码中的“一 cache line 八条边”是该布局/平台背景下的注释;跨平台应重新核对结构尺寸和 cache line。相邻边共享顶点,SIMD 批次的合法性仍依赖内容排列和写回顺序,不能任意把所有边并发执行。

2.2 碰撞是有限候选集合#

角色布料和环境布料分别组织附着变换、重力、阻尼、pin 顶点及碰撞实例;碰撞计时项细分 sphere、capsule、tapered capsule 和 geometry。SetCollisionInst/AddCollisionInst 显式受数组容量约束,说明布料不是无条件查询全世界所有碰撞体。Framework 还能把自定义 capsule 定义作为实体 extension 接入。

这种方式把碰撞复杂度限制在局部范围,但遗漏候选、过大位移、低更新频率和不合适的简化碰撞体都会影响穿透表现。对新项目应分别控制候选数量、约束迭代数、时间步和显示细度;单独增加布料顶点往往不能修好候选漏失。

2.3 模拟网格不必等于显示网格#

clothBridgeSimGfx 保存各 LOD 的显示映射、pin radius、vertex weight;phMorphController 通过映射和权重将低细度模拟结果转到更高细度显示网格。ApplySimulationToMesh 检查模拟/显示 LOD 与映射数量的一致性。这让渲染细节不必线性放大约束成本。

LOD 切换需要状态迁移:SwitchLOD 不是只改一个整数,它从旧网格映射顶点位置,或者执行 Morph。函数仍有“支持跨 LOD 跳跃”的 TODO,且映射有效性检查可见,因此不能推断任意层级跳转都已无缝解决。升降阈值分别存储,为滞回策略提供接口;实际阈值属于内容配置。

2.4 并行与阶段边界#

环境布料/绳索具有 sysTaskContext 路径,并按任务代码、stack、input 扣除可用 scratch;也存在直接执行的分支。clothManager 提供 PreUpdate/Update/PostUpdate,保存 active/ready、骨架、上次位置和任务管理器。工作线程只能在约定的生命周期内访问这些借用数据,模拟结束也不自动意味着显示顶点缓冲已可被任意线程覆盖。

这一设计适合固定容量及协处理器硬件。移植现代任务系统时,应保持“输入快照→模拟→发布→渲染消费”的所有权关系,重新测量批量和 scratch,而非逐字保留 SPU 预算。

3. Fragment:预定义拓扑上的破坏与重新组合#

fragType/fragInst 延续定义与实例分离;fragPhysicsLODGroup 有高、中、低物理 LOD,每层组织 children、groups、composite bounds、惯量、阻尼、自碰撞关系和连接信息。这些关系说明破坏不仅是换一张材质,而是改变物理组、可绘制部件和活动实例的对应关系。

FRAG_MAX_NUM_CHILDREN/GROUPS 的 bitset 容量为 256,同时部分计数接口是 u8。这不是“任意资源均可恰好包含 256 个有效孩子”的保证;导出器必须同时检查编码、计数和保留值约束。固定编号和位集使损伤状态处理紧凑,也限制超大型破坏资源的粒度。

Fragment 使用 cache/mesh cache 管理实例资源,并提供 paging 通知。某个部件脱离后,其模板、绘制资源和物理数据不能因为原父实体不再可见便立即卸载。破坏峰值因此常表现为实例数、碰撞对、临时网格和资源引用共同增长。

fragManager::SimUpdate 根据 1/timeSlice 与可调 BreakingFrameRateLimit 更新禁止破坏标记。这是明确的负载保护机制入口,但仅凭此函数不能断言所有破坏路径都受它控制;它使用传入时间片,也不能简单解释为测得的全局显示 FPS。低负载与高负载时行为可能不同,新项目应区分可降级视觉破碎与必须保持的玩法结果。

4. 玻璃:几何、物理和渲染更新的联合生命周期#

bgGlassManager 提供预留堆、physics instance pool、Create/Destroy/TransferOwner、Update/Sync 和 UpdateBuffers。Create 同时涉及 bgBreakable、bgDrawable、phGlassInst;因此玻璃破碎的完成条件跨越裂纹几何、碰撞和显示资源。

接口证据支持“有池、有明确同步与所有权转移”,不支持声称所有玻璃均运行同一种裂纹算法。此专题未逐条验证裂纹传播内核。实践启发是让表现系统有明确的最大实例数与生命周期回收点,并在爆炸连锁场景监控资源和物理增长,而不只看玻璃 shader 时间。

5. 粒子:规则驱动实例与共享索引分批工作#

ptxManager 组织 Effect/Emitter/Particle rules、时间线、关键帧属性与实例。Update 拆成 Setup、Parallel、Finalize、Cleanup;回调效果、本地效果具有独立同步标记和 semaphore。规则是共享内容,实例保存时间、活动粒子及运行状态。

ptxupdatetask 使用原子加从共享 emitter item 数组领取一个批次,逐个调用 UpdateParallel。这属于动态分批领取工作,不能称为每个粒子一个 Job,也不是独立 worker deque 的 work stealing。末批截断防止数组越界,WaitForAll 等待任务句柄并清理线程 ID。

发射器若带 PTXEMITINSTFLAG_ON_MAIN_THREAD_ONLY 会跳过并行任务;回调/演化数据还需要相应线程准备。因此增加 worker 数并不能消除游戏回调或收尾阶段的串行成本。发射器之间粒子数量差异大时,固定 item 数批量也可能产生长尾。

性能要同时观察 CPU 更新、碰撞、规则求值、排序、绘制提交、透明 overdraw 和粒子纹理驻留。大量小粒子可能受 CPU 管理限制,大面积烟雾则可能受像素带宽限制;用粒子总数作为唯一指标会混淆瓶颈。

GPU 命名不等于 GPU 全包#

gpuptfx/ptxgpubase.h 定义 Drop/Mist/Ground 专用系统;其中 RAIN_UPDATE_CPU 为 1 && RSG_PC。因此在这份源码的 PC 分支,雨更新可在 CPU 进行,不能因为目录叫 gpuptfx 就说全部天气粒子都由 GPU 模拟。各后端的数据读取、heightmap 和缓冲生命周期需单独分析。

6. 植被与程序化分布#

plantsgrass 从局部碰撞三角形构造 pngPlantLocTri,记录 seed、面积、材质、顶点颜色/scale,附近缓存与分帧更新配合多级距离淡入淡出。pngGrassModel 同时持 drawable 与 geometry,前者还承担内存管理角色。这是一种用紧凑分布参数重建大量视觉实例的思路。

头文件存在固定局部 triangle cache、实体 cache、轮转更新常量;这些是该模块默认定义,不代表 GTA 所有草木统一使用这些值。grass、tree 和游戏植被路径还各有实现,本文只把它们归入同类职责,不把 plantsgrass 视作唯一实际路径。

新项目需关注相机快速运动时的重建峰值、种子稳定性、LOD 滞回、透明覆盖和碰撞查询依赖。程序化分布减少存储并不意味着运行时生成免费。

7. 新项目的取舍和验证#

值得借鉴必须明确的限制建议实验(未执行)
模拟/显示网格解耦映射质量及 LOD 状态迁移连续升降 LOD、瞬移、极端附着速度
SoA 边约束与批量任务顶点写冲突、尾批和 cache 行比较批次大小、迭代误差与耗时
Fragment 预定义拓扑内容编码容量、损伤组复杂度连锁破坏时 pool、接触对、网格峰值
有界视觉活动集合降级可能改变可见行为帧时压力下破坏与特效的优先级一致性
规则/实例分离回调和共享数据限制并行带回调与纯本地效果分别采样
透明度/距离分级密度和 overdraw 不线性固定粒子数改变屏幕覆盖率

8. 源码证据#

文件入口
cloth_verlet_update.cpp92–137 约束修正;141 起 SoA;512 起角色更新;586 起任务;836 起候选容量
clothcontroller.h、cpp75 LOD 接口;cpp 278 切换、916 起显示映射
clothbridgesimgfx.hphMapData/phMorphController 与显示映射
clothmanager.h自定义碰撞 extension、实例和阶段
typephysicslod.h31 容量、45 起 LOD/children/groups
fragment manager.cpp288–309 时间片与禁止破坏标记
glassmanager.h池、创建、同步与缓冲更新
ptxmanager.h、ptxupdatetask.cpp分阶段、回调 fence;cpp 118–200 批量执行
ptxgpubase.h24–26 PC CPU 更新;48–54 专用系统
plantsmgr.h40–66 LOD/cache;117 起分布数据

进一步阅读:物理、动画、渲染、性能。