← ALL ARTICLES

破坏系统

全库目录221
本文目录19

一堵墙受到撞击以后,裂缝出现并不意味着整堵墙都应变成独立碎块。仍然连接地基的部分需要留在原处,脱离的部分需要得到质量、碰撞和速度,通道是否打开还必须与玩法判定一致。破坏系统把这些变化组织成一次从资产连接到物理状态的转换。

本文采用预切分刚体模型:碎块形状在离线阶段确定,运行时只改变连接和组合。伤害分配使用明确的教学规则;它便于复现断裂顺序,材料的真实断裂与应力传播由专门模型处理。

碎块资产与连接

几何分区

预切分资产保存每块的封闭表面、局部变换、碰撞凸包、质量、质心和关于自身质心的惯性张量。质量可由密度乘体积得到,空洞和不同材料分别积分。渲染网格负责断面外观,碰撞形状负责接触,二者通过同一碎块编号关联。

一种离线切分方法是给定种子点,对每对种子构造等距平面,把原物体裁到离某个种子最近的一侧。保留下来的区域形成该种子的 Voronoi 单元。裁面补成封闭断面后,才可计算体积和碰撞。种子落在薄壁附近时会生成很薄的碎块;资产步骤据厚度、体积和凸包误差筛掉退化结果,并重新生成相邻关系。本文以通过这些检查的预切分资产为输入,参考程序只处理它的数值和拓扑。

黏结与支撑

把碎块编号作为节点,相接触的断面作为无向黏结边。边保存两端编号、断面中心、法线、面积和剩余强度。几何接近本身不足以定义连接:两块相邻但可独立滑动的部件,应由资产明确决定是否黏结。

支撑集合记录与世界固定的节点。节点0固定、连接为0—1—2时,节点1和2都通过连接链获得支撑。固定性属于整个连通分量;只检查碎块自身是否标记固定,会错误地让节点1和2掉落。NVIDIA Blast 的支持图同样用未断连接确定分组,并允许连接到世界;具体资产层次与本文的平面图模型分别定义。

冲击与断裂

径向伤害分配

事件接纳时冻结当前拓扑版本、世界撞击点与各簇姿态。完整黏结的两端属于同一簇,其离线断面中心先转换成该簇局部坐标,再由该簇当前变换送到世界空间,与撞击点求距离。整件资产尚未分裂时也可把撞击点变回统一资产坐标;多个动态簇分别运动后,各簇使用自己的变换。设半径为R、距离为d,径向权重取:

wi=max⁡(0,1−di/R),Δhi=Dwi∑jwj.w_i=\max(0,1-d_i/R),\qquad \Delta h_i=D\frac{w_i}{\sum_j w_j}.

事件接纳先检查R为正有限数、D为非负有限数,边强度和位置也必须有限;R为零的点伤害需要另定义命中边规则,不能代入本式。D和剩余强度h使用同一套游戏伤害单位,距离和R使用米。D是事件携带的损伤预算,既不代表牛顿,也不直接代表焦耳。若希望由冲量产生损伤,项目需给出有单位的材料映射并单独校准;参考实现直接接收D。

接纳记录保存本次各候选边ID、距离和对应拓扑版本。比如某簇整体平移10米,撞击点也在其新位置附近,按原始资产变换测距会错误地把附近黏结排除。异步准备与容量等待期间沿用已记录的距离,不随簇后来移动重新定位同一次撞击;重复事件仍返回原登记结果。批次按稳定事件顺序处理,前一事件已经断开的边从后一事件的有效集合中去掉,再按上述权重规则归一化剩余权重。

分母只累计仍完整且位于半径内的连接。分母为零时事件不改变连接;否则把每条连接更新为max(0, h - Δh)。某条连接扣到零以后,超出的损伤在本规则中耗散,保留的预算也不会再次分配,所以一条很弱的连接不会把剩余损伤反复传给其他连接。

例如两条边的强度为10和4,到撞击点的距离为0米和1米,R为2米、D为6。权重为1和0.5,损伤分别为4和2,剩余强度得到6和2。再施加一次参数相同、编号不同的事件,结果为2和0,第二条边断裂。由此可以沿事件记录重算断裂时刻;若直接按碎块到撞击点的距离删掉节点,就会丢失这条累积过程。

这个模型没有解算弯矩、应力集中或裂纹尖端。悬臂远端受力是否导致根部断裂,必须由应力模型向对应黏结写入损伤,单靠局部径向距离推不出来。Blast 将材料损伤函数交给使用者定义;本文的权重是独立教学选择。

支撑传播

同一物理步中的伤害先批量写回,再移除所有剩余强度为零的边。从每个尚未访问的节点开始,用栈遍历有效邻居,收集一个连通分量。分量与支撑集合相交则保持固定,否则成为动态簇。每个节点和边只需访问常数次,全图重算为O(V+E)。

text
for each unvisited node:
    stack = [node]; group = {}
    while stack is not empty:
        v = pop(stack)
        if v is visited: continue
        mark v visited; add v to group
        push all neighbors joined to v by intact bonds
    supported = group intersects support_nodes
    emit(group, supported)

把上一节两条边依次映射为0—1和1—2,节点0固定。第一次伤害后图仍连通,三块都留在固定簇;第二次伤害后形成{0,1}和{2},只有2激活。如果另有完整边0—2,那么断开1—2仍不会使节点2脱落。这条反例说明断裂边数不能直接决定新刚体数。

动态簇内再次断裂时,也对该簇的当前连接求分量。已经激活的节点不能再作为固定支撑;固定支撑集合与物体的动态状态必须在同一版本下读取。图版本用于防止上一帧的分组任务覆盖最新伤害结果。

动态簇重建

质量与惯性

一个脱落分量可以先作为包含多个碰撞子形状的复合刚体,连接继续断裂后再分开。设各块质量为m、世界质心为c,则簇质量和质心为:

M=∑imi,c=∑imiciM.M=\sum_i m_i,\qquad c=\frac{\sum_i m_i c_i}{M}.

惯性必须关于新的簇质心计算。先把每块自身惯性张量旋转到同一坐标系,再使用平行轴定理:

I=∑i(RiIiRiT+mi[(ri⋅ri)1−ririT]),ri=ci−c.I=\sum_i\left(R_i I_i R_i^T+m_i\left[(r_i\cdot r_i)\mathbf1-r_i r_i^T\right]\right),\qquad r_i=c_i-c.

两个块沿X轴放置,质量分别为1和3千克,质心位置为0和2米,自身绕Z惯性分别为1/6和1/2千克·平方米。簇质心为1.5米,绕Z惯性为1/6 + 1×1.5² + 1/2 + 3×0.5² = 11/3。直接相加两个自身惯性只得到2/3,漏掉质心偏移后,同样扭矩会产生过大的角加速度。

碰撞子形状沿用资产凸包;设簇的局部到世界旋转为R_c,它们相对簇质心的局部位置写为R_cᵀ(c_i - c),局部旋转为R_cᵀR_i。当簇坐标轴与世界一致时,位置才简化为c_i - c。例如簇绕Z旋转90°,世界偏移(1,0,0)在簇局部应为(0,−1,0);直接保存世界偏移会让碰撞子形状多转90°。重设质心以后若仍沿用原来的局部偏移,碰撞就会整体错位。运行时重新生成凸包会改变形状和质量分布,因此需要同步重算这些量。

质量坐标与刚体接口

计算结果进入刚体之前,先固定质量坐标系。上式中的质心和旋转均在世界空间,因此得到的是世界惯性张量I_world。簇坐标轴为R_c时,簇局部张量为I_local = R_cᵀ I_world R_c。例如局部张量为diag(1,2,3),簇绕Z轴旋转90°后,世界张量为diag(2,1,3);把世界对角值直接作为局部惯量,会交换物体两个轴的转动响应。

接收完整局部张量的求解器直接使用I_local。PhysX的setMassSpaceInertiaTensor接收质量主轴上的三个主惯量,因此还要把对称张量分解成I_local = Q Λ Qᵀ,其中Q的列为正交主轴,Λ为对应主惯量;调整轴符号使Q为右手旋转,成对保存轴与特征值。以簇质心为刚体原点时,质量局部姿态为平移零、旋转Q,碰撞子形状仍使用前述簇局部坐标。设置质量、质量局部姿态和主惯量后,再设置速度。若刚体原点另选位置,质量局部姿态的平移还要包含该原点到质心的局部偏移。

资产准备阶段检查质量为正有限、惯性对称且主惯量为正有限,并检查重建张量与输入的误差。退化碎块返回准备失败,不能把零惯量当作普通动态物体参数提交。主惯量重复时主轴可以不唯一,正确性由重建出的张量决定;保存确定的基底选择便于重放对照。以上质量接口见PhysX PxRigidBody。

速度场与冲量

切分瞬间,原刚体中心为c₀、线速度为v₀、角速度为ω。新簇中心处的速度由刚体速度场给出:

v=v0+ω×(c−c0).v=v_0+\omega\times(c-c_0).

新簇继承ω,之后分别积分。以上述新簇为例,原中心X为0,沿Y速度为1米/秒,绕Z角速度为2弧度/秒。偏移为1.5米,叉积增加Y速度3米/秒,新簇Y速度为4米/秒。把每块都赋成v₀,会抹掉旋转贡献。

仅改变分组时,这种赋值保持原速度场。若要加入爆炸冲量J,则另外计算Δv=J/M,作用点p产生的角速度增量为I⁻¹((p-c)×J)。冲量只能进入动力学一次;若碰撞求解器已将接触冲量计入原刚体速度,再把同一个J施加给新簇,就会重复加速。

物理提交与失败恢复

物理世界在安全同步点提交替换。先按新分组准备刚体、子形状、质量和速度;准备失败时保留原表示与待处理事件。全部准备成功后,停用旧刚体及其碰撞,注册新刚体,更新节点到刚体的归属,最后发布新的拓扑版本。渲染与玩法查询在这个版本上切换。

这次提交对外应表现为一个完整状态。若新旧碰撞同时参与一次求解,相同表面会生成重复接触;若先移除旧碰撞却没有准备好新碰撞,角色会在空档穿墙。引擎适配层负责把这些操作放进物理系统允许的写入阶段,CPU图算法本身不能证明接入时序正确。

事件接纳与候选准备

事件接纳先以(资产实例,事件编号)查询待处理表与已应用表,检查与入队在同一模拟提交入口串行执行。同ID同参数已经待处理时返回原暂缓状态,不再加入第二份损伤;已经应用时返回对应版本;同ID不同参数直接拒绝。准备失败保留原待处理身份与参数,重试仍引用它,不能另建一份相同编号的候选。

损伤写回、分组和刚体替换共享一份候选版本。先复制当前连接强度与节点归属,在候选版本上按稳定事件顺序扣减损伤、求分量和准备物理对象,权威查询仍读取旧版本。准备失败则丢弃候选物理对象、保留事件待重试,当前图和碰撞都不变;不能先把图公布为已开门,再保留堵门的旧碰撞。

安全点提交

准备任务只预建几何、质量和节点归属;动态旧簇在此期间仍会移动,因此它保存的世界姿态与速度不能直接用于提交。到安全物理写入阶段时再次核对基础拓扑版本仍匹配,并从旧簇当前姿态重建各新簇世界质心、形状变换,再用该时刻的v₀和ω继承速度。预建质量保存在簇局部坐标,提交时沿用局部主惯量与质量姿态;需要计算世界角速度增量时,以提交时的R_c重建I_world=R_c I_local R_cᵀ,再与世界冲量和力臂相乘。旧簇在等待期间转过90°时,准备时保存的世界惯性已经过期,不能与新世界力臂混用。提交前待施加的独立爆炸冲量也按事件编号核对是否已进入旧簇,避免重复施加。版本匹配后,才完成旧表示停用、新表示注册、节点归属替换,并把事件编号登记为已应用;全部更新作为一个物理场景提交点对外可见。

若准备期间又到达新伤害,排队进入下一候选批次,旧异步分组不覆盖新版本。

失败恢复

无法让场景内部失败回滚的宿主先完成容量与资源预留,提交只执行已准备好的不失败操作;可见提交阶段仍可能失败时,保存替换清单并在恢复阶段恢复整套旧表示,期间暂停查询与求解。

对外广播只有已提交事件,接收端重复编号返回已有版本。断边事件到达但刚体准备失败,不提前确认成功,也不永久消耗事件编号;否则重试会被去重层丢弃。图状态、物理表示与事件登记的提交顺序因此属于同一个机制,连通算法算对不能证明这次交接正确。

预算与生命周期

预算先区分承担玩法的障碍和只影响外观的细碎片。前者在权威逻辑中保留碰撞身份,后者可以使用粒子。假设脱落分量有20个碎块、预算只允许4个动态刚体,可以把每个连通分量作为一个复合体;如果仍超过预算,就保留明确的粗碰撞代理,并用渲染碎片表现细节。

代理的误差需要与玩法一起定义。例如门洞宽度决定玩家能否穿过,代理必须保留该通道,不能用包住整个门框的单个凸包封死它。若任意合并无法满足误差约束,就延迟装饰碎片激活,将预算留给关键碰撞。预算筛选依据稳定编号和显式优先级,避免同一事件在不同机器上得到不同通道。

一个可以直接执行的预算规则先把分量分为关键碰撞与装饰两组,关键性由资产玩法标签和当前任务通道共同判定。每个关键分量沿用原碎块凸包组成复合刚体,每个分量占一个刚体槽;按稳定编号全部预留后,剩余槽再按装饰分量体积从大到小分配,体积相同按编号排序。没有槽的装饰分量只生成无权威碰撞的渲染碎片。20个碎块若仍组成4个关键连通分量,4槽即可保留完整动力学;若已经形成5个关键分量,4槽无法同时满足这个要求。

粗代理由资产预先保存的若干凸子形状组成,并登记允许替换的节点集合与玩法空间误差;候选分量必须恰好匹配其节点集合才可采用,代理子形状不能跨过已断开的关键通道。门框代理保留左右柱和横梁三个子形状,不能取整框的凸包。代理通过对应主问题的角色胶囊通道查询和交互射线检查后,才进入可用目录;运行时只检查集合与误差契约,不临时猜一个包围盒。代理减少形状数量,并不自动减少互相独立的刚体数。关键分量仍超过槽数时,本次拓扑提交保持旧版本、事件进入有界等待队列并返回暂缓结果,待回收或增加预算后重试;队列满则拒绝新破坏请求。这样容量不足表现为明确的失败或背压,不会让拓扑已经断开、关键碰撞却被悄悄丢弃。

动态碎片速度持续低于睡眠阈值后可进入休眠;静止不等于可以删除。回收前先确认它已经退出权威碰撞与交互查询,再释放渲染和物理资源。复用对象池槽位时增加代次,异步任务必须同时匹配槽位和代次,才能写入当前碎片。

权威事件与重放

联网破坏以权威端的图状态为准。事件包含资产实例、事件编号、拓扑版本、损伤参数以及最终断裂边或分组结果。接收端先检查事件编号,重复事件不再扣强度;版本连续时应用,版本缺口则请求快照或等待缺失事件。按“收到一次就扣一次”处理重传,会让同一次撞击造成多次断裂。

重放从资产初始强度与支撑开始,按已记录顺序应用事件。采用断裂边列表可直接复现拓扑;采用浮点损伤参数时,还要固定运算规则和排序,否则阈值附近可能出现分歧。物理接触的轨迹可以采用状态校正,拓扑一致性与刚体轨迹一致性分别验证。

只显示破坏结果的客户端可以消费断边与分组,但继续计算伤害的恢复端需要完整的剩余强度。强度10降到6时拓扑没有变化;恢复成10后再扣7会保留连接,正确的6再扣7则断裂。因此可继续模拟的快照保存资产版本、实例身份、提交序号、每条边剩余强度、支撑集合、节点归属及同一物理边界的簇姿态和速度。没有断边的损伤提交也推进状态序号,不能仅靠拓扑变化编号识别它。

本页的恢复路线保存每次提交后被修改边的绝对剩余强度,以及相应分组和事件回执。恢复先装入快照,再按连续提交序号应用后续记录;序号缺口停止推进并补取记录,相同序号校验内容后跳过。绝对值写入避免重传再次扣损伤。若采用从原始事件重新计算的另一条路线,记录还必须包含接纳时冻结的边距离和稳定事件顺序,不能用恢复时的新姿态重新测距。

待处理事件与已提交回执分别恢复。待处理记录保存原事件身份、参数、冻结距离及顺序,在恢复出的当前图上重新准备;已提交事件直接返回原回执。物理对象从已提交状态重建,准备完成前暂停查询和求解,再从明确的物理边界继续积分。提交状态、事件回执与恢复日志必须共同持久化,或全部纳入宿主的同一耐久提交协议;仅广播断边不承担这份恢复职责。

实现与验证

参考实现使用Python标准库,包含径向伤害、连通分量和沿X轴分布的平面刚体簇计算。它接收有效节点编号和非负有限损伤数据;完整三维张量、凸包创建和物理事务由目标工程提供。

powershell
python 知识库/examples/retained_review/destruction/test_reference.py

2026-10-23本机执行6项测试通过,覆盖两次累积损伤、断边后的支撑分组、完整连接、质量与惯性以及速度继承。测试中的数值可按正文公式独立重算。固定回放还应加入替代连接、空影响半径、重复事件、激活失败、预算代理与回收代次场景。

引擎验证时先记录每次提交前后的节点归属、碰撞数量、质心和速度,再观察门洞与旋转碎块。单步检查旧碰撞停用和新碰撞启用是否属于同一提交;引擎导入、刚体激活、网络重放与性能测试尚未执行,CPU参考结果只支持上述数值和图关系。

相关主题

参考资料