Teardown 的体素物理:碰撞、破坏与动态结构
Teardown 为什么能让任意形状的体素实时碰撞、穿透、破坏并重新成为刚体?从 Voxel Volume、碰撞检测、材料破坏、Connectivity 到 Joint 与约束求解,拆解其完全可破坏世界背后的物理架构。
《Teardown》最令人印象深刻的地方,并不只是“所有东西都能炸”。
墙壁可以被一枪一枪凿穿,车辆能够直接撞进建筑;一根承重连接被切断后,原本属于场景的一大片结构会脱离、倾倒,与地面碰撞,再压住其他碎片。门、机械结构和绳索上的 Joint 又能随着结构破坏继续工作,或者在连接处消失后断开。
如果把这一切放进传统基于 Polygon Mesh 的物理世界里,会立刻遇到一连串麻烦:
- 任意破坏会不断产生新的凹几何;
- 动态凹 Mesh 的碰撞很难直接处理;
- Mesh 被切开后需要重新生成碰撞表示;
- 结构分离后需要重新建立刚体;
- Joint 所连接的几何本身可能已经不存在;
- 几百甚至几千个碎块落下后,又要继续稳定地碰撞和堆叠。
Teardown 没有试图逐个解决这些问题。
它采取了一个更根本的办法:
改变世界的几何表示,让碰撞、破坏和结构分离都变成适合实时计算的问题。
Teardown 使用的是专门为游戏开发的自定义体素物理和图形引擎,而不是 PhysX、Havok 或 Bullet。1 Dennis Gustafsson 后来也明确说明,Teardown 的碰撞检测直接工作在 voxel volumes 上。2
这意味着 Teardown 最值得研究的地方,并不是某一种特别神奇的刚体 Solver,而是从 Voxel Volume → Collision → Destruction → Connectivity → Rigid Body 形成的一整套架构。
本机样本与证据边界
本文在公开资料之外,还检查了本机 Windows 版 teardown.exe、随游戏提供的 Lua 脚本和 .vox 模型。EXE 的 SHA-256 为 c8228c8748fef01f55c30db33ebedd5853903d96c53025a7949ea6c337e5f7ca。安装包有可读的 Lua 游戏脚本与 API 声明,但没有原生 C++ 引擎源码;下文提到的 PE 导入、类型名与着色器字符串只能证明该样本包含相应代码或数据线索,不能代替函数调用图或运行时追踪。
1Teardown 为什么需要自己的物理引擎?
1.1从表面几何变成体积几何
传统游戏模型通常首先是一层表面。
一个墙体可能由三角形描述:
Triangle Mesh
↓
表面在哪里?但“墙里面是什么”并不是这个表示天然知道的事情。
这对不可破坏场景没有太大问题。一堵墙只需要告诉物理引擎:
这里不能过去。
一旦要求玩家可以在任何位置挖洞,事情就复杂了。破坏不仅改变外轮廓,还会不断暴露新的内部表面。
Teardown 从一开始就选择了不同的问题表示:
Voxel Volume
↓
这个空间位置有没有材料?Dennis 将传统破坏的困难概括得很直接:Polygon Mesh 主要描述物体表面,切割以后会产生数值精度、任意新几何和物理引擎 convexity 等问题;而 Teardown 的对象从一开始就是规则网格上的 voxel volume。3
这使“墙里面是什么”不再需要特殊处理。
因为墙本来就是一个有内部体积的数据结构。
1.2世界并不是一个巨大的 Voxel Grid
这里很容易产生另一个误解:
Teardown 是否像 Minecraft 一样,把整个世界装进一个巨大的三维体素数组?
不是。
Dennis 在介绍 Teardown 时明确说明,世界并不是一个包含数十亿 voxel 的单一 Volume,而是由数千个较小的 voxel volumes 组成。4
例如:
World
├── House wall
├── Roof
├── Door
├── Table
├── Car body
├── Car door
└── ...每一个 Volume 内部仍然保持规则的局部体素网格,但整个 Shape 可以拥有自己的空间变换。
于是可以出现:
Local voxel grid
████
████
███
↓ Body Transform
╱██
╱████
███体素本身不需要因为物体旋转而重新排列。
旋转的是整个 Volume。
Dennis 在 2024 年回顾原版 Teardown 引擎时进一步说明,Teardown 的 Shape 使用的是 dense voxel format:每个 Shape 内部保存一个未压缩的规则三维网格;这种方式访问非常快,但空白区域同样会占内存,因此资产往往需要拆成多个较紧凑的 Shape。5
这也是为什么 Teardown 的物理对象结构不能简单理解成“一个世界网格”。
1.3磁盘上的 .vox 与运行时 Shape
本机 data/vox/bomb.vox 以 VOX 和版本号 150 开头。它的 SIZE 块给出 的模型范围,XYZI 块列出 42 个非空体素;每条记录用四个字节保存 和调色板索引。文件还包含 RGBA、MATL 等块。这个分块布局与 MagicaVoxel 的格式说明相符。6
这说明磁盘文件列举非空体素,不等于 Dennis 所说的运行时 Shape 内部的未压缩规则网格。同样,官方 GetShapeSize 返回的是 Shape 的体素尺寸和单个体素的米制缩放;文档给出的默认缩放为 0.1 米,并非所有资源都被写死为这个尺度。7 不能把 .vox 文件的每条四字节记录当成运行时每格的内存占用,也不能只凭文件头推断碰撞表示。
1.4Body、Shape 与 Voxel
从官方 API 可以进一步看出其对象层级。
一个 Shape 始终属于某个 Body; destruction 发生时,它甚至可以被转移给新的 Body。8
可以把它粗略理解为:
Body
├── Shape
│ └── Voxel Volume
├── Shape
│ └── Voxel Volume
└── ...Body 承担刚体状态:
- Transform
- Linear Velocity
- Angular Velocity
- Mass
- Center of Mass
而 Shape 更接近几何与材料表示。
官方 API 既可以查询 Body 的质量与质心,也允许修改 Shape 的 Density。9
因此:
Voxel 数量、Shape 数量和 Rigidbody 数量不是一回事。
一辆体素汽车有几十万个 voxel,并不意味着物理世界中存在几十万个 BoxCollider。
这正是理解 Teardown 性能的第一步。
不是“一格一个 BoxCollider”
如果把每个 voxel 都创建成一个独立 BoxCollider,体素稍微多一些,Broad Phase、Collider 管理和 Contact 数量就会迅速失控。Teardown 的碰撞对象是整个 voxel volume,而 voxel 是这个 Shape 内部的几何数据。
2体素碰撞究竟如何工作?
2.1Teardown 避开了动态 Concave Mesh 问题
在传统 Mesh Physics 中,一个被炸得千疮百孔的物体可能变成极度复杂的凹形状。
如果继续沿用 Mesh 表示,往往会面对类似流程:
破坏 Mesh
↓
产生新的任意几何
↓
重新建立 Collision Mesh
↓
Convex Decomposition / Collider Cooking
↓
重新参与物理Teardown 改变了这个问题。
一个非常凹的物体,在体素空间里仍然只是一组 occupied cells:
111111111
100000001
101111101
101000101
101111101
100000001
111111111从数据结构角度,并不存在一个额外的“这是凹多边形”问题。
它只是:
哪些 voxel 存在,哪些 voxel 为空。
Dennis 明确表示 Teardown 的碰撞检测在 CPU 上进行 voxel-versus-voxel collision;渲染则由 GPU 完成。4
因此真正特殊的不是:
Teardown 有一个特别强的动态 Concave Mesh Collider。
而是:
它根本没有把这些东西表示成传统 Concave Mesh。
2.2Collision 仍然需要从对象对走到 Contact
“Voxel-vs-Voxel”并不代表物理引擎可以暴力遍历两边所有 voxel。
如果两个 Shape 分别有几十万个 voxel:
逐格穷举显然没有现实意义。
刚体碰撞仍然需要解决两个层次的问题:
Dennis 在 2025 年的物理演讲中把 Teardown 的物理步骤概括成两个主要阶段:
- Collision Detection:找到靠近或重叠的对象对并生成 Contact;
- Constraint Solver:根据这些 Contact 和 Joint 更新刚体速度。2
而 Teardown 的 Quicksave 技术文章透露了更重要的一层:
voxel object 除主体素数据之外,还有一份单独的 physics representation,同样使用 voxel 数据,但格式不同;physics、culling、rendering、lighting 还各自拥有可由原始数据重建的空间加速结构。10
所以架构更接近:
Authoritative Voxel Data
│
├── Physics Representation
├── Physics Acceleration Structure
├── Rendering Structure
├── Lighting Structure
└── Culling Structure这是一项非常重要的工程选择:
同一个世界可以拥有统一的权威数据,但不同子系统不必共享完全相同的数据结构。
碰撞系统可以针对“快速找到可能接触的 voxel”建立自己的表示,而不必迁就渲染器。
2.3任意旋转的 Voxel Volume 怎么碰撞?
真正困难的地方也由此出现。
假设两个对象都有自己的局部规则网格:
Shape A Shape B
████ ███
███ rotation ████
██ ↘ ███它们进入世界空间后,可以拥有任意位置和旋转。
碰撞系统必须最终回答:
- 哪些区域可能重叠?
- 哪些 solid voxel 真正发生接触?
- Contact Position 在哪里?
- Contact Normal 是什么?
- 应该生成多少个 Contact?
这才是 Teardown voxel collision 真正技术含量很高的部分。
但在这里必须区分已经公开的事实和合理但未经证实的实现猜测。
Teardown 的完整 Narrow Phase 并未公开
公开资料可以确认:Teardown 使用自研 voxel-vs-voxel collision、CPU 计算、独立 physics representation 和物理空间加速结构。
但 Dennis 并没有公开原版 Teardown Narrow Phase 的完整算法与数据结构。因此不能仅凭第三方复刻项目,就断言它具体使用 Octree、BVH、Spatial Hash、某种 OBB 遍历,或者某一种固定的 Contact Manifold 生成方式。
所以最稳妥的抽象是:
Spatial acceleration
↓
Candidate voxel volumes
↓
Custom voxel-vs-voxel narrow phase
↓
Contact generation
↓
Constraint solver而“中间究竟怎样高效遍历两个任意旋转的体素网格”,仍然是 Teardown 技术中最值得研究、但公开资料最有限的一块。
2.4脚本查询能说明什么?
官方 API 把 QueryRaycast 的命中距离、法线和 Shape 句柄返回给 Lua;可选的 radius 大于零时,它会执行带厚度的查询。查询前还可以设置物理层、碰撞掩码及要排除的 Body 或 Shape。11 本机脚本 data/script/player_locomotion.lua 给出一个实际用途:角色蹲伏时用半径 0.1 的查询检查头部附近空间,判断跳跃与落地动画时则向下查询地面距离。
这些调用能验证“游戏逻辑如何使用碰撞结果”,却不能揭示原生窄相怎样遍历两个体素 Volume。QueryAabbShapes 也只是对脚本开放的范围查询,不能由函数名反推出物理广相采用了哪一种树或网格。这里的 QueryRaycast 是物理/场景查询;官方 FAQ 所说的核心体素渲染光线追踪,是另一项工作。1
2.5GJK 并不能直接当成 Teardown 的答案
Dennis 很早以前就开发过自己的刚体物理引擎,并曾使用 GJK 作为 Convex Collision 的核心算法。
但这不能反过来证明:
Teardown 使用 GJK 做 voxel-vs-voxel collision。
Teardown 后来专门将 Collision Detection 改写成适应 voxel 的形式。Dennis 在 2026 年的采访中再次提到,当初将碰撞检测重写为 voxel collision 时,他原本担心性能会很差,但结果比预想中更可行。3
因此更合理的技术关系是:
传统刚体经验
Convex Collision / Contact / Solver
│
↓
Teardown
Custom Voxel Collision
+
Rigid Body Constraint Solver刚体数学可以延续,但几何碰撞表示已经换了一套问题。
3碰撞为什么可以变成“穿透”?
这可能是 Teardown 和普通游戏物理在体验上最明显的不同之一。
普通刚体世界中,一个高速物体撞向墙面:
Object → Wall
↓
Contact
↓
Solver Impulse
↓
Stop / Bounce / SlideContact Solver 的目的之一,本来就是阻止两个 Solid Object 继续互相穿入。
如果墙的 Collision Geometry 永远不变,那么无论物体有多快:
● → ███████████物理系统最终只能尝试:
● ← ███████████或者让它停下来、滑开。
Teardown 多出来的能力是:
碰撞发生以后,造成碰撞的几何本身也可以改变。
3.1材料不是只有颜色
Teardown 的一个 voxel 并不需要把完整的一组物理和视觉属性全部存下来。
Dennis 介绍过它的材料系统:每个 voxel 主要保存一个 8-bit palette index,因此每格只需要一个 byte;Palette Material 再描述颜色、roughness、emissiveness、reflectivity,以及 wood、metal、foliage 等 physical material type。12
于是:
Voxel
↓
Palette Index
↓
Material
├── Color
├── Roughness
├── Reflectivity
├── Emissive
└── Physical Material Type物理破坏还进一步区分材料等级。
Teardown 官方 Modding 文档明确列出了四档 Hardness:13
| Hardness | 典型材料 | 普通枪械 | Explosives |
|---|---|---|---|
| Soft | Glass、Wood、Plastic、Plaster | ✓ | ✓ |
| Medium | Concrete、Brick、Weak Metal | ✓ | ✓ |
| Hard | Hard Masonry、Hard Metal | ✗ | ✓ |
| Unbreakable | Heavy Metal、Rock | ✗ | ✗ |
这说明 Teardown 所谓“材料”并不只是视觉表面。
它直接参与:
这种作用能不能修改当前 voxel geometry?
3.2MakeHole 几乎直接暴露了破坏模型
官方 API 中有一个非常有代表性的函数:
MakeHole(position, r0, r1, r2)这里三个半径分别作用于:
r0:Soft Material;r1:Medium Material;r2:Hard Material。
并且要求:
API 返回的甚至是实际被切掉的 voxel 数量。14
于是同一个爆炸或破坏事件可以自然表现成:
Soft
████ ████
██ ██
Medium
██████ ██████
Hard
████████ ████████
Unbreakable
██████████████████也就是说:
所谓硬度,并不一定意味着“Solver 给出更大的反作用力”;它首先可以意味着这次破坏能够从碰撞几何中移除多少材料。
这正是理解 Teardown “穿透感”的关键。
3.3穿透的关键,是碰撞边界本身在退让
想象一个高速物体或 Projectile 撞上一堵可破坏墙。
普通物理:
Object
↓
Wall Contact
↓
Collision Response而 Teardown 可以形成另一条路径:
这张图是解释“碰撞边界可以随破坏改变”的概念模型,并非从 EXE 还原出的固定调用顺序。MakeHole 公开了按材料切除体素的操作,不能证明每次车辆撞击都会按图中同一条分支、在同一物理步内调用它。
这意味着物体并不是简单地“无视 Collider 穿过去”。
而是:
- 撞到当前最外层材料;
- 破坏规则允许这一层 voxel 消失;
- 原来的碰撞边界随之消失;
- 运动继续;
- 物体遇到更深一层材料。
连续发生以后,从宏观上就呈现出:
穿透。
因此 Teardown 的一个非常漂亮的特性是:
Collision Response 与 Destruction 可以共同改变下一次 Collision Detection 要面对的几何。
碰撞不再只是对世界状态做“速度响应”。
它还能改变世界的几何状态。
3.4Projectile 也有 Strength,但不要凭空发明穿透公式
Teardown 的官方 Shoot API 明确包含:
Shoot(origin, direction, type, strength, maxDist)其中 strength 是 Projectile 的强度缩放。15
因此游戏至少明确拥有两边的信息:
Projectile
└── Strength
Voxel / Material
└── Destruction class这足以支撑“不同武器对不同材料产生不同破坏”的系统。
但目前公开资料并没有给出类似:
这样的真实穿透能量公式。
同样,车辆、高速碎块撞击环境时,Teardown 显然能够产生 Collision-driven Destruction;但“Contact Impulse 如何准确映射成 voxel destruction”的内部公式也没有公开。
因此更严谨的理解应该是:
Teardown 的穿透感来自动态可修改的碰撞几何、材料破坏规则以及 Projectile / Impact 系统的共同作用;具体的能量衰减和冲击破坏公式不能从现有公开资料中确定。
这一区别很重要。
它避免把一种游戏物理效果误解成完整的连续材料力学模拟。
4破坏为什么能让建筑真正分裂?
能够挖洞还不够。
如果我们只是:
████████████
██████ ████
█████ ███
██████ ████把几格 voxel 清空,那么最多只得到一个洞。
真正让 Teardown 成为 Teardown 的问题是:
什么时候一部分结构已经不再属于原来的整体?
4.1Voxel Connectivity
Teardown 的官方资产文档明确规定了 voxel 的 Connectivity:
voxel 必须通过面相接,才能正确地保持连接;仅通过边或角接触的 voxel,在物体受损或变成动态物体时会分离。13
也就是典型的六邻域连接:
+Y
|
-X -- V -- +X
|
-Y
±Z 前后对于结构而言:
██████████
██████████
██
██
██
██████████如果中间连接被彻底切掉:
██████████
██████████
██
██
██████████上方和下方已经不再属于同一个 Connected Component。
这一步并不是刚体 Solver 能决定的。
它属于:
Topology。
4.2SplitShape 直接按照 Connectivity 分块
官方 API 几乎把这一机制直接暴露了出来:
SplitShape(shape, removeResidual)文档说明:
按照 connectivity 将一个 Shape 拆成多个 Shape。
同时还有:
IsShapeDisconnected(shape)
IsStaticShapeDetached(shape)用于查询 Shape 是否已经出现分离部分。16
于是整个破坏链条可以概括成:
这解释了为什么把一根柱子真正切断之后,顶部可以整体掉下来。
关键并不是:
“这一块建筑累计受到了 1000 点 Damage。”
而是:
从体素拓扑上,它已经与原来的结构断开。
4.3破坏首先是拓扑问题,然后才是动力学问题
这是理解 Teardown 整套系统最重要的观点之一。
很多传统破坏系统关注:
Impact
↓
Fracture Pattern
↓
Spawn predefined chunksTeardown 更接近:
Modify Volume
↓
Topology Changed
↓
Find Components
↓
Create Physical Pieces
↓
Rigid Body Simulation也就是说:
倒塌不是破坏系统直接“播放”出来的;破坏系统首先改变哪些材料仍然存在,然后物理系统处理已经分离出来的对象。
这也解释了为什么它的结果具有很强的连续性。
你可以:
- 从左边切;
- 从右边切;
- 只剩一根连接;
- 再把最后一格连接打掉。
系统不需要事先准备四种不同的“Destroyed Version”。
4.4Static Geometry 也可以因为破坏而变成 Dynamic
Teardown API 中甚至专门提醒:
一个最初创建为 Static 的 Body,也可能因为 destruction 而变成 Dynamic。9
这正符合玩家看到的现象:
建筑的一部分
原本属于世界
↓
连接被切断
↓
Detached
↓
Dynamic Body
↓
Fall / Rotate / Collide与此同时,Shape 永远属于某个 Body,但其 ownership 可以在 destruction 中改变。官方 API 也允许显式将 Shape 移动到另一个 Body。8
这说明 Teardown 的动态破坏不只是:
修改一张 voxel texture。
它还会改变场景的物理对象拓扑。
4.5这不是 FEM 结构力学
这里也需要避免过度解读。
Teardown 的建筑倒塌效果很有说服力,但不能因此推导出:
每个 voxel 都在实时计算应力、应变和裂纹传播。
公开出来的核心机制更加离散:
Material destruction
+
Voxel connectivity
+
Shape splitting
+
Rigid body simulation这意味着一栋建筑在还保持 voxel connectivity 时,并不等价于一个正在进行有限元应力分析的连续介质。
Teardown 的聪明之处恰恰在这里:
它没有模拟现实世界中的所有破坏原因,而是选择了足够一致、足够便宜,又特别适合游戏交互的一组规则。
5动态结构如何在破坏后继续工作?
当 Structure 可以不断 Split 后,又会出现一个更棘手的问题:
原本挂在这些 Shape 上的 Joint 怎么办?
假设一扇门:
Wall
│
Hinge
│
Door Shape
████████
████████现在门被炸成:
███ ███
███ ███
↑
Hinge area原来的 Door Shape 已经不再是一个完整连通区域。
Joint 不能继续抽象地说:
“我连接旧 Door。”
因为旧几何已经发生变化。
5.1Joint 连接的是 Shape
官方 API 明确写道:
一个 Joint 始终连接两个 Shape。
可以通过:
GetJointShapes(joint)
GetJointOtherShape(joint, shape)取得它连接的具体 Shape。17
这意味着 Joint 与破坏拓扑并不是两套完全分离的系统。
而是:
Joint
├── Shape A
└── Shape B一旦 Shape 被拆分,Joint 的 attachment 也必须重新解释。
5.2Shape 分裂后,Joint 也可能被重新连接
2026 年 Dennis 在介绍 Teardown Multiplayer 时,给出了非常珍贵的内部信息。
为了在网络上同步 destruction,游戏会把一次破坏拆成一系列确定性的命令,其中包括:
cut hole in this shape at voxel coord x,y,z
change ownership of that shape
reconnect joint to this shape这句话几乎直接说明了动态破坏需要同时处理:
Voxel content
Shape ownership
Joint attachment例如:
Before
Shape B
│
Joint
↓ destruction
Shape B1 + B2 + B3
↓
Joint → B2如果 Joint 所依附的部分本身已经不存在,则连接也可能失效。
官方 API 同样提供:
DetachJointFromShape(joint, shape)
IsJointBroken(joint)进一步说明 Joint attachment 本身就是可以动态改变的状态。17
这正是 Teardown 的动态结构能够显得“自然”的重要原因:
Joint 并不是贴在一个永远不会变化的 Collider 上,而是与会发生拓扑变化的 Shape 系统一起维护。
6最后还是要回到刚体 Solver
到目前为止,Teardown 最特殊的部分都是:
- Voxel Geometry;
- Voxel Collision;
- Material Destruction;
- Connectivity;
- Shape Split;
- Joint Reassignment。
但是一旦生成 Contact 和新的 Rigid Body,后面的动力学反而没有那么神秘。
Dennis 在 2025 年的公开演讲中说明,Teardown 使用的是:
Projected Gauss-Seidel(PGS) / Sequential Impulse
形式的约束求解器。2
它会迭代处理:
Contact constraints
Friction constraints
Joint constraints
...一次 Contact 会计算 Impulse,并立即修改相关刚体的线速度和角速度,然后继续处理下一条 Constraint。
可以粗略理解为:
Dennis 还明确给出过原版 Teardown 的一个具体参数:
Teardown 使用 8 次 Solver Iteration。2
脚本层也公开了时间边界:官方 API 的 server.update(dt) 每次调用的步长固定为 秒,但某一渲染帧可能不调用;server.postUpdate() 在物理更新之后调用。19 这能帮助模组把施加约束与读取结果放到合适阶段;它不等于公开了原生求解器内部是否还有子步,不能拿来推断碰撞与破坏任务的精确执行顺序。
因此 Teardown 的架构有一个很有意思的分界:
| 环节 | Teardown 最特殊的地方 |
|---|---|
| Geometry | Voxel Volume |
| Collision | Custom voxel-vs-voxel |
| Destruction | 直接修改 voxel |
| Structural separation | Connectivity / Split |
| Joint topology | 随 Shape 变化 |
| Constraint Solver | 相对传统的 PGS / Sequential Impulse |
换句话说:
Teardown 并没有重新发明刚体动力学的全部数学。它主要重新设计了“什么东西进入刚体物理系统”。
7为什么这样的物理还能实时运行?
看到这里,一个自然的问题是:
几千万、几亿 voxel,再加上随时可能发生的破坏,为什么没有直接把 CPU 压垮?
答案首先还是:
不要把 voxel 数量等同于 Physics Object 数量。
7.1Voxel 是几何数据,不是独立刚体
一个包含十万个 voxel 的墙体,在物理世界里仍然可以只是:
1 Body
+
1 or several Shapes
+
Voxel data而不是:
100000 Bodies
+
100000 BoxColliders这使大量细小几何细节能够存在,而不必让物理世界同时维护同等数量的独立对象。
7.2专用 Physics Representation
前面提过,Dennis 明确表示 voxel object 存在一份单独的 physics representation,并且 physics 使用自己的 acceleration structures。10
这体现了一种很经典、也很值得借鉴的引擎设计:
主体素数据负责表达:
世界是什么。
派生结构负责回答:
某个系统怎样最快地使用这个世界。
这样破坏时只需要修改权威 voxel state,再更新或重建受到影响的派生结构。
而不是强迫 Physics、Rendering、Lighting 全部使用一种“万能格式”。
本机 EXE 还留有 CollisionDataTask 与 PaintSlicesTask@VoxelObject 的类型字符串,以及着色器中的体素 chunk 数、chunk 大小和 mip 偏移字段。这些线索与“碰撞数据、绘制数据分别准备”的架构相容;GPU 着色器中的 chunk 参数也不能推翻前文所述的原版 CPU Shape 稠密网格。单靠字符串仍无法确定任务是否在每次破坏后触发、更新覆盖多大范围,或 CPU 与 GPU 的同步时机。官方 FAQ 将光线追踪列为核心体素渲染的一部分;本机 PE 与类型字符串则表明该版本同时包含 OpenGL 与 D3D12 渲染路径。1
7.3SIMD、Multithreading 与 Data Parallelism
Dennis 在 2026 年回顾 Teardown 的优化过程时表示,Early Access 阶段投入了大量时间优化 Physics 和 Destruction,并使用 SIMD 和 Multithreading 来利用现代 CPU。3
Teardown 官方 FAQ 也指出,引擎高度 Multithreaded,不过根据场景不同,游戏可能受 CPU 或 GPU 限制,并不意味着能够始终吃满所有硬件资源。1
这一点与碰撞检测的工作性质非常契合。
如果已经获得大量可能碰撞的 Object Pairs:
Pair 1
Pair 2
Pair 3
Pair 4
...不同 Pair 的 Contact Detection 在很多情况下可以独立进行,因此非常适合数据并行。
Dennis 在 BSC 2025 中也特别指出:
Collision Detection 相对容易并行;真正难并行的是后面的 Constraint Solver。2
7.4大规模倒塌真正麻烦的是 Simulation Island
这也是一个很有反差的地方。
Teardown 最恐怖的性能场景未必是:
屏幕里存在很多 voxel。
而可能是:
大量 Dynamic Bodies 同时互相接触。
刚体物理可以把互不相关的对象拆成不同 Simulation Islands:
Island A Island B
A — B — C D — E
│
F不同 Island 可以独立求解。
但把整栋建筑炸塌后:
▣ ▣
▣ ▣ ▣
▣▣▣▣
▣▣▣▣▣
██████大量 Body 通过 Contact 连成一张大图:
ONE LARGE SIMULATION ISLANDPGS / Sequential Impulse 又具有明显的数据依赖:
Solve Contact A-B
↓
B velocity changes
↓
Solve Contact B-C第二条 Constraint 希望看到第一条已经修改过的状态,因此简单地把整个 Solver 平均分给多个线程并不容易。
Teardown 的做法长期以来主要是通过不同 Simulation Islands 做并行,而 Dennis 后来开发下一代体素引擎时,专门重新研究了大型 Island 的并行 Solver、Graph Coloring 和 Substepping。220
不要把 Dennis 的“新引擎”实现写成 Teardown
Dennis 在 2024~2025 年公开展示的 Sparse Voxel、Substepping、Parallel Solver 等改进属于正在开发的下一代引擎,并不等同于原版 Teardown 的实现。它们很有价值,因为恰好反映了 Teardown 旧架构暴露出来的性能瓶颈,但两者需要严格区分。
8Teardown 真正解决了什么问题?
如果只观察最终效果,很容易把 Teardown 理解成:
一个“物理特别强”的游戏。
但从架构来看,它更有意思的地方其实是一次问题重构。
传统完全可破坏世界需要不断面对:
Dynamic Concave Geometry
Mesh Boolean
Fracture
Collider Recooking
Convex Decomposition
Changing TopologyTeardown 把核心几何换成规则体素之后,很多问题被重新表达成:
Voxel Occupancy
Voxel Removal
Voxel Material
Connectivity
Shape Split
Voxel Collision于是原本彼此分散的问题开始共享同一套语言:
这也解释了 Teardown 最特别的“穿透感”。
普通物理系统在碰撞发生后,主要改变的是:
物体怎么运动。
而 Teardown 还可以改变:
下一帧究竟还有什么东西可以被碰撞。
一堵墙不是永远存在的 Static Collider。
它是一块可以被修改的体积数据。
当材料被切除,Collision Geometry 也随之改变;当最后的连接消失,Topology 改变;当 Component 分离,又会产生新的 Physical Object;Joint 还必须重新寻找自己属于哪块结构。
最终,Teardown 所实现的并不是某一个孤立的“破坏算法”。
而是一条连续的系统:
Voxel Geometry → Voxel Collision → Material Destruction → Connectivity → Dynamic Topology → Rigid Body Physics。
它最值得借鉴的设计思想也正来自这里:
面对一个极其困难的问题,有时最有效的优化不是把原来的算法做得越来越复杂,而是重新选择一种数据表示,让原本困难的问题变得天然容易表达。
注释
-
Tuxedo Labs,Teardown FAQ。官方明确说明游戏使用基于 voxel technology、专门为 Teardown 构建的自定义物理与图形引擎;FAQ 同时说明引擎高度多线程,实际运行可能受 CPU 或 GPU 限制。 ↩ ↩2 ↩3 ↩4
-
Dennis Gustafsson,Parallelizing the Physics Solver — BSC 2025,Better Software Conference,2025。Dennis 在演讲中明确说明 Teardown 拥有直接在 voxel volumes 上执行碰撞检测的自定义物理引擎,Constraint Solver 使用 Projected Gauss-Seidel / Sequential Impulse;原版 Teardown 使用 8 次 Solver Iteration,并通过 Simulation Islands 对独立物理组进行并行处理。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
80 Level 对 Dennis Gustafsson 的采访,Teardown Developer Breaks Down Multiplayer and Voxel Destruction Tech,2026。Dennis 说明传统 Surface Mesh 在动态破坏中的内部表示、数值精度和 convexity 难题,以及 Teardown 将碰撞检测改写为 voxel collision 后,通过 SIMD 与 Multithreading 持续优化 Physics 和 Destruction。此处是开发者直接采访,但发布平台并非 Tuxedo Labs 官方站点。 ↩ ↩2 ↩3
-
Game Developer,Bryant Francis 对 Dennis Gustafsson 的采访,How beautiful voxels laid the way for Teardown's heist-y framework,2020。Dennis 在采访中说明世界由大量较小 voxel volumes 构成,碰撞在 CPU 上进行 voxel-versus-voxel 计算。 ↩ ↩2
-
Dennis Gustafsson,Year summary,Voxagon Blog,2024。Dennis 在介绍下一代引擎 Sparse Voxel Format 时明确对比指出,Teardown 原有 Shape 使用未压缩规则三维网格的 Dense Voxel Format。 ↩
-
ephtracy,MagicaVoxel
.voxfile format。格式说明定义VOX头、SIZE和XYZI分块,以及每条XYZI记录的四个一字节字段;本文的尺寸与非空体素数来自本机bomb.vox样本。 ↩ -
Tuxedo Labs,Teardown Scripting API — GetShapeSize。官方文档区分 Shape 的网格尺寸与单个体素的米制缩放,并将 0.1 米标为默认缩放。 ↩
-
Tuxedo Labs,Teardown Scripting API,
GetShapeBody、SetShapeBody。官方文档说明 Shape 始终由 Body 拥有,并可能在 destruction 过程中被转移到新的 Body。 ↩ ↩2 -
Tuxedo Labs,Teardown Scripting API,
GetBodyMass、GetBodyCenterOfMass、SetShapeDensity。这些接口表明刚体质量/质心与 Shape material density 在引擎中是明确存在的不同属性;公开文档没有说明破坏后的 Mass Properties 具体如何增量更新。 ↩ ↩2 -
Dennis Gustafsson,Teardown quicksave,Voxagon Blog,2020。文章说明 Teardown 世界包含数千个独立 voxel volumes,大型关卡约可包含数亿 voxel;voxel object 拥有单独的 physics representation,并为 physics、rendering、lighting、culling 建立可重建的空间加速结构。 ↩ ↩2
-
Tuxedo Labs,Teardown Scripting API — Scene queries。官方文档说明
QueryRaycast的返回值、可选半径和查询过滤接口;脚本示例来自本机随游戏提供的data/script/player_locomotion.lua。 ↩ -
Dennis Gustafsson,The Spraycan,Voxagon Blog,2020。文章说明 Teardown 使用 8-bit voxel material palette,每个 voxel 的表示只需一个 byte;Material 同时描述视觉参数和 wood、metal、foliage 等 physical material type。 ↩
-
Tuxedo Labs,Teardown Modding — Materials / Voxel Connectivity。官方文档给出 Soft、Medium、Hard、Unbreakable 材料等级及不同工具能否破坏它们,同时明确规定 voxel 需要以面相连才能保持结构连接。 ↩ ↩2
-
Tuxedo Labs,Teardown Scripting API — MakeHole。
MakeHole分别接受 Soft、Medium、Hard 材料的破坏半径,并返回被切除的 voxel 数量。 ↩ -
Tuxedo Labs,Teardown Scripting API — Shoot。官方 Projectile API 暴露
type、strength与maxDist;该接口证明 Projectile Strength 的存在,但并未公开完整的材料穿透能量模型。 ↩ -
Tuxedo Labs,Teardown Scripting API — SplitShape / IsShapeDisconnected。官方说明
SplitShape根据 connectivity 将 Shape 拆成多个 Shape,并可移除小型 residual chunks 以减少新 Shape 数量。 ↩ -
Tuxedo Labs,Teardown Scripting API — Joint。
GetJointOtherShape的文档明确说明一个 Joint 始终连接两个 Shape;API 同时提供GetJointShapes、DetachJointFromShape与IsJointBroken等动态结构操作。 ↩ ↩2 -
Dennis Gustafsson,The unlikely story of Teardown Multiplayer,Voxagon Blog,2026。Dennis 说明多人版将 destruction 表达为确定性命令流,包括在指定 voxel 坐标切洞、改变 Shape ownership、重新连接 Joint 等;这为 Teardown 的动态拓扑过程提供了直接的一手描述。 ↩
-
Tuxedo Labs,Teardown Scripting API — server callbacks。官方文档将
server.update(dt)定义为固定 0.0166667 秒、每帧至多两次的回调,并说明server.postUpdate()在物理更新后执行。 ↩ -
Dennis Gustafsson,Year summary,Voxagon Blog,2024。文中所述 Sparse Voxel Format、Substepping 与 Parallel Solver 属于 Dennis 正在开发的下一代引擎,用于对比说明原 Teardown 架构暴露出的限制,不应误写成 Teardown 已采用的实现。 ↩
CONTINUE EXPLORING