资讯动态

Claude-of-Duty物理引擎从零手写:BVH加速结构、扫掠胶囊角色控制器与PBD布娃娃系统

发布时间:2026/9/26 20:55:34 来源:尧图企业网站定制
Claude-of-Duty物理引擎从零手写BVH加速结构、扫掠胶囊角色控制器与PBD布娃娃系统【免费下载链接】Claude-of-DutyA Call of Duty-quality FPS in Three.js, built from a single prompt.项目地址: https://gitcode.com/gh_mirrors/cl/Claude-of-DutyClaude-of-Duty 是一款纯 Three.js 构建的浏览器第一人称射击游戏而它最硬核的部分是那个完全从零手写的物理引擎——不依赖任何物理库。这篇文章带你拆解它的三大核心组件BVH 加速结构、扫掠胶囊角色控制器与 PBD 布娃娃系统看看没有现成轮子时一个 FPS 的物理世界是如何搭建起来的 为什么从零手写物理引擎市面上有成熟的物理库如 Rapier、Cannon.js但这个项目选择在 src/physics/index.js 中直接声明立场No physics library。手写带来了三个好处确定性所有子系统以 120 Hz 固定步长推进随机数统一来自引擎时钟物理行为可复现——这对项目的自动化截图比对工具链至关重要零依赖、零体积运行时唯一依赖是three本身与游戏深度耦合弹道穿透、布娃娃死亡动画、爆炸冲击波都是为射击玩法定制的整个物理子系统就 10 个文件新人完全读得动 文件职责bvh.js静态世界三角形烘焙 分箱 SAH BVHcharacter.js扫掠胶囊角色控制器滑动、上楼梯ragdoll.jsPBD 布娃娃求解器骨骼胶囊链rigidbody.js6 自由度刚体碎片、弹壳penetration.js多层材质子弹穿透math.js射线/线段相交等基础几何selftest.js无头自检与性能基准快速体验3 分钟跑起来游戏零美术资产——所有纹理、模型、声音都是代码在加载时程序化生成的。本地运行只需git clone https://gitcode.com/gh_mirrors/cl/Claude-of-Duty cd Claude-of-Duty npm install npm run dev # 打开 http://127.0.0.1:5173点击画布锁定鼠标后WASD 移动、左键射击。想单独验证物理系统而不打开浏览器直接运行node src/physics/selftest.js即可后文会细讲。BVH 加速结构2.9 万三角形0.25 微秒一次射线检测FPS 里最频繁的查询是射线检测瞄准线打到哪子弹穿了几层墙如果每次都对全部三角形暴力求交2.9 万三角形 × 每帧数千条射线就是灾难。BVHBounding Volume Hierarchy包围盒层次结构是标准解法把所有三角形装进一棵二叉树每次射线检测先与节点包围盒快速剔除平均只需深入对数级节点。这个项目的实现细节见 bvh.js分箱 SAH 建树不排序、不递归用 12 个分箱近似表面积启发式Surface Area Heuristic选最优切分面全部迭代完成无递归栈溢出风险扁平化布局顶点、法线、材质索引全部存进Float32Array/Uint8Array等类型化数组节点元数据是 2 个整数的紧凑数组CPU 缓存友好构建后零分配查询走预分配栈结果写入调用方提供的记录对象避免每帧 GC 抖动最终成绩29k 三角形烘焙成 1.4 万个节点建树约 22 ms单次射线检测0.25 微秒。每个三角形还带着材质表面标签混凝土、木头、玻璃等 12 种命中结果直接告诉上层——子弹打墙上掉灰还是打木箱起火星靠的就是它。扫掠胶囊角色控制器上楼梯不卡、500 m/s 不穿墙第一人称角色的碰撞体普遍是胶囊体比球体贴合人体比盒子便宜。真正的难点有两个——① 连续扫掠Swept检测。离散检测是这一步后我插进墙里了吗扫掠检测是这条移动路径上胶囊扫过的体积与谁相交。角色控制器每步调用sweepCapsule做真·连续碰撞测试所以即便 500 m/s 的位移在单步内横穿 0.2 m 的薄墙也绝不会穿模。② 平面栈滑动。胶囊撞上墙要贴着墙滑过去但如果角色卡墙角、沿楼梯棱线走单一法线的滑动会在两条棱之间反复弹射。控制器采用了 character.js 中的方案最多收集5 个接触平面5-plane crease stack剩余位移对每个平面依次投影裁剪若被 A 面推出去又撞上 B 面就沿两面的交线棱线滑动——这是 Quake 引擎 30 年前就验证过的经典技巧。上楼梯则是另一套巧思见 move() 方法落地状态下水平移动前先把胶囊抬升 stepHeight0.42 m走完水平位移后再落回。台阶面只要低于抬升高度对水平扫掠就不可见楼梯问题被优雅地绕开了。最后还有一道 0.32 m 的吸附距离让角色稳稳贴住地面。每步 move() 五连击 1. 去穿透 2. 抬升 3. 平面栈滑动 4. 落回吸附 5. 地面探测速度归玩家状态机所有控制器只负责裁剪位移——物理手感与运动逻辑彻底解耦这也是值得新手借鉴的设计。PBD 布娃娃系统中枪倒地为什么不会爆炸角色死亡后变成的软趴趴的布娃娃Ragdoll是 FPS 里最容易被做砸的环节。ragdoll.js 的注释开门见山解释了技术选型15 根骨骼胶囊 单侧世界接触 120 Hz 步长下基于位置的动力学PBD配合高斯-赛德尔迭代是无条件稳定的——骨骼不可能凭空获得能量身体只会自然沉降不会嗡嗡发抖或爆开。关键结构共享关节粒子每根骨骼是两个粒子的线段相邻骨骼共用关节粒子关节脱臼在结构上就不可能发生只需约束旋转默认人形骨架humanoidSpec 按 7.5 头身比例定义 15 根胶囊骨盆→脊柱→胸腔→颈→头 四肢每根带独立的摆锥角、扭转限制与质量每迭代按序解算 4 类约束骨长刚性距离→ 摆锥 → 扭转带阻尼→ 世界接触胶囊 vs BVH 库仑摩擦防炸保险单步粒子位移上限 0.35 m静止 0.6 s 自动休眠中枪时的冲击用1/(1d²)衰减下发给各粒子见 applyImpulse爆头会猛烈甩头但整个身体不会被传送走——这就是游戏里击杀动画自然不违和的原因。顺带一提刚体碎片与多层子弹穿透静态碰撞和角色之外射击玩法还需要两块拼图刚体rigidbody.js弹壳、碎屑等小物件走完整 6 自由度模拟——半隐式欧拉积分 序贯冲量接触解算 库仑摩擦与恢复系数。碰撞检测用少量探针球近似盒体 8 个角球、胶囊 2~3 个成本远低于精确求交效果与主流射击游戏一致。静止休眠的刚体完全跳过计算满街弹壳几乎零开销。多层穿透penetration.js子弹携带一个穿透预算以参考材料厚度计命中后按材质penDepth消耗预算、按距离衰减伤害、从随机源取偏转量最多穿透 6 层。穿墙时会在入口和出口各发射一次bullet:impact事件特效层据此决定入口是弹坑、出口是掉渣。没有画面可看用 selftest 验证物理物理系统的失败往往是看不见的胶囊悄悄穿墙、布娃娃偷偷涨能量截图根本发现不了。所以项目自带一个无头自检脚本 selftest.js用 120×120 网格地面 墙体 楼梯 40 个实例化木箱搭一个测试关卡发射2000 条随机射线与暴力逐三角形求交对拍要求 0 误差让角色以 500 m/s 单步冲墙验证扫掠检测不穿模统计 20 万条射线的耗时断言亚毫秒运行方式node src/physics/selftest.js这种先写可验证的失败模式再写实现的思路比看起来正常可靠得多——对新手尤其值得学。总结这套手写物理引擎的 3 个核心经验数据布局即性能BVH 用类型化数组扁平化存储、构建后零分配0.25 微秒的射线检测不是玄学是内存布局的胜利连续检测是角色控制器底线扫掠胶囊 平面栈滑动 抬升上台阶三招组合解决了 FPS 手感的全部痛点选无条件稳定的求解器做角色死亡动画PBD 的位置约束天然耗散能量布娃娃永远只沉降、不爆炸整套代码不到 4000 行全部在 src/physics/ 目录下配套契约说明见 ARCHITECTURE.md。想动手学物理引擎这是一个能完整读完、还能跑起来验证的绝佳样本 【免费下载链接】Claude-of-DutyA Call of Duty-quality FPS in Three.js, built from a single prompt.项目地址: https://gitcode.com/gh_mirrors/cl/Claude-of-Duty创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑