讲师中心 微信公众号
AI工具推荐 视频效率加速

如何在 Three.js 中正确集成 cannon-es 实现物理模拟

阿雪大大_9260

阿雪大大_9260

发布时间:2026-07-10 16:55:09

|

425人浏览过

|

来源于php中文网

原创

本文详细讲解如何在现代 Web 环境(ES 模块 + importmap)中正确引入并使用 cannon-es 为 Three.js 场景添加刚体物理,解决因版本冲突、加载方式错误或初始化缺失导致的页面空白问题。

本文详细讲解如何在现代 web 环境(es 模块 + importmap)中正确引入并使用 `cannon-es` 为 three.js 场景添加刚体物理,解决因版本冲突、加载方式错误或初始化缺失导致的页面空白问题。

在初学者尝试将物理引擎集成到 Three.js 项目时,最常见的报错现象是:页面完全空白,控制台出现 ReferenceError: CANNON is not defined 或 Cannot instantiate cyclic dependency 等错误,甚至无任何提示直接白屏。这通常并非代码逻辑错误,而是由以下关键原因导致:

  • ❌ 混用旧版 cannon.js(已停止维护)与新版 cannon-es(TypeScript 重构、ESM 原生支持);
  • ❌ 在 <script type="module"> 中错误地通过 <script src="...cannon.js"> 同步加载非模块脚本(违反 ESM 规范);
  • ❌ importmap 中 Cannon 的路径未指向有效的 ESM 兼容版本(如 cannon-es.min.js),或 CDN 不支持跨域/模块解析;
  • ❌ 忘记创建 CANNON.World() 实例、未调用 world.step(delta) 更新物理状态,或未同步物理体位置到 Three.js Mesh;
  • ❌ 缺少必要依赖(如 Clock 获取时间步长)、未设置重力、未添加接触材质(导致物体“穿透”地面)。

✅ 正确做法是:统一使用 cannon-es(推荐 v0.19+),通过 importmap 声明标准化导入路径,并在 requestAnimationFrame 循环中严格按“更新物理 → 同步渲染”顺序执行

以下是可直接运行的最小可行示例(已精简冗余代码,聚焦物理核心):

抖音下载器(Node.js)
抖音下载器(Node.js)

抖音无水印视频下载和文案提取工具

下载
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Cannon-es + Three.js Physics Demo</title>
  <style>body { margin: 0; overflow: hidden; }</style>
  <!-- ✅ 正确声明 importmap:仅保留必需项,cannon-es 指向 CDN 上的 ESM 兼容构建 -->
  <script type="importmap">
    {
      "imports": {
        "three": "https://unpkg.com/three@0.167.1/build/three.module.js",
        "three/addons/": "https://unpkg.com/three@0.167.1/examples/jsm/",
        "cannon-es": "https://cdn.jsdelivr.net/npm/cannon-es@0.19.0/dist/cannon-es.min.js"
      }
    }
  </script>
</head>
<body>
  <script type="module">
    import * as THREE from 'three';
    import { Clock } from 'three';
    import * as CANNON from 'cannon-es'; // ✅ 使用 cannon-es,非 cannon.js

    // 1️⃣ 初始化物理世界
    const world = new CANNON.World();
    world.gravity.set(0, -9.82, 0); // 地球重力

    // 2️⃣ 配置物理材质(避免穿模、控制摩擦/弹性)
    const physicsMaterial = new CANNON.Material();
    const contactMaterial = new CANNON.ContactMaterial(
      physicsMaterial, physicsMaterial,
      { friction: 0.1, restitution: 0.7 } // 摩擦小、弹性适中
    );
    world.addContactMaterial(contactMaterial);

    // 3️⃣ 创建地面刚体(mass=0 表示静态)
    const groundBody = new CANNON.Body({ mass: 0, material: physicsMaterial });
    groundBody.addShape(new CANNON.Plane());
    groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
    world.addBody(groundBody);

    // 4️⃣ 创建下落立方体刚体
    const cubeBody = new CANNON.Body({ mass: 1, material: physicsMaterial });
    cubeBody.addShape(new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5)));
    cubeBody.position.set(0, 5, 0);
    world.addBody(cubeBody);

    // 5️⃣ Three.js 渲染层
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 3, 5);

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    document.body.appendChild(renderer.domElement);

    // 立方体 Mesh(视觉表现)
    const geometry = new THREE.BoxGeometry(1, 1, 1);
    const material = new THREE.MeshStandardMaterial({ color: 0x00ff88 });
    const cubeMesh = new THREE.Mesh(geometry, material);
    cubeMesh.castShadow = true;
    scene.add(cubeMesh);

    // 地面 Mesh
    const groundGeometry = new THREE.PlaneGeometry(20, 20);
    const groundMaterial = new THREE.MeshStandardMaterial({ 
      color: 0xaaaaaa, 
      roughness: 0.8,
      metalness: 0.2 
    });
    const groundMesh = new THREE.Mesh(groundGeometry, groundMaterial);
    groundMesh.rotation.x = -Math.PI / 2;
    groundMesh.receiveShadow = true;
    scene.add(groundMesh);

    // 光源
    const light = new THREE.DirectionalLight(0xffffff, 1);
    light.position.set(5, 10, 7);
    light.castShadow = true;
    scene.add(light);

    // 时间控制器
    const clock = new Clock();

    // ? 主渲染循环:物理更新 + 渲染同步
    function animate() {
      requestAnimationFrame(animate);

      const delta = Math.min(clock.getDelta(), 0.1); // 限制最大步长防卡顿
      world.step(delta); // ✅ 关键:必须调用!否则物理不演进

      // ✅ 同步物理体位置/旋转到 Three.js Mesh
      cubeMesh.position.copy(cubeBody.position);
      cubeMesh.quaternion.copy(cubeBody.quaternion);

      renderer.render(scene, camera);
    }
    animate();

    // ✅ 响应窗口大小变化
    window.addEventListener('resize', () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    });
  </script>
</body>
</html>

? 关键注意事项总结

  • 永远不要混用 cannon.js 和 cannon-es:前者是 CommonJS/UMD,后者是纯 ESM;cannon-es 是官方推荐的现代替代品。
  • importmap 中 Cannon 的 URL 必须返回 .js 文件且支持 ESM:推荐使用 jsDelivrunpkg 的 .min.js 构建(已预编译为兼容 ESM 的 IIFE)。
  • 物理世界必须显式 step():Three.js 渲染帧与物理帧需解耦,world.step(delta) 是驱动物理演化的唯一入口。
  • 位置同步不可省略:CANNON.Body 的 position/quaternion 与 THREE.Mesh 的对应属性无自动绑定,必须手动 copy()。
  • 静态物体设 mass: 0:如地面、墙壁,否则会受力移动,影响稳定性。
  • 调试技巧:若仍白屏,打开浏览器 DevTools → Console 查看具体报错;检查 Network 标签页确认 cannon-es.min.js 是否成功加载(HTTP 200)。

掌握以上要点后,你不仅能解决“屏幕变白”问题,更能建立起对物理引擎与渲染引擎协同工作的清晰认知——这是构建交互式 3D 应用的基石。

热门AI工具

更多
Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

相关专题

更多
html版权符号
html版权符号

html版权符号是“©”,可以在html源文件中直接输入或者从word中复制粘贴过来,php中文网还为大家带来html的相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

4915

2023.06.14

html在线编辑器
html在线编辑器

html在线编辑器是用于在线编辑的工具,编辑的内容是基于HTML的文档。它经常被应用于留言板留言、论坛发贴、Blog编写日志或等需要用户输入普通HTML的地方,是Web应用的常用模块之一。php中文网为大家带来了html在线编辑器的相关教程、以及相关文章等内容,供大家免费下载使用。

2872

2023.06.21

html网页制作
html网页制作

html网页制作是指使用超文本标记语言来设计和创建网页的过程,html是一种标记语言,它使用标记来描述文档结构和语义,并定义了网页中的各种元素和内容的呈现方式。本专题为大家提供html网页制作的相关的文章、下载、课程内容,供大家免费下载体验。

2530

2023.07.31

html空格
html空格

html空格是一种用于在网页中添加间隔和对齐文本的特殊字符,被用于在网页中插入额外的空间,以改变元素之间的排列和对齐方式。本专题为大家提供html空格的相关的文章、下载、课程内容,供大家免费下载体验。

2559

2023.08.01

html是什么
html是什么

HTML是一种标准标记语言,用于创建和呈现网页的结构和内容,是互联网发展的基石,为网页开发提供了丰富的功能和灵活性。本专题为大家提供html相关的各种文章、以及下载和课程。

4539

2023.08.11

html字体大小怎么设置
html字体大小怎么设置

在网页设计中,字体大小的选择是至关重要的。合理的字体大小不仅可以提升网页的可读性,还能够影响用户对网页整体布局的感知。php中文网将介绍一些常用的方法和技巧,帮助您在HTML中设置合适的字体大小。

2521

2023.08.11

html转txt
html转txt

html转txt的方法有使用文本编辑器、使用在线转换工具和使用Python编程。本专题为大家提供html转txt相关的文章、下载、课程内容,供大家免费下载体验。

2289

2023.08.31

html文本框代码怎么写
html文本框代码怎么写

html文本框代码:1、单行文本框【<input type="text" style="height:..;width:..;" />】;2、多行文本框【textarea style=";height:;"></textare】。

2108

2023.09.01

Conan私有仓库搭建教程
Conan私有仓库搭建教程

本专题系统的讲解Conan私有仓库的搭建流程,涵盖仓库服务部署、存储目录配置、用户认证、权限划分和远程地址添加,并介绍内部C++依赖包的上传、下载及版本维护方法。

0

2026.09.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Echarts实战项目—疫情数据展示
Echarts实战项目—疫情数据展示

共13课时 | 1.5万人学习

WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 20.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn