08-刚体约束 Constraint

发布于 2025-07-24 00:26 747 字 4 min read

做产品前,先别急着写代码:我是怎么判断一个点子值不值得做的想偷卷?但微信不支持md文档?这个软件助你!新手小白如何开发练手项目?前端常见安全问题 + 防御方法 + 面试回答吉比特(雷霆游戏)前端二面问题总结吉比特27前端实习面试纷享销客前端实习一面08-刚体约束 Constraint07-监听碰撞事件和获取碰撞信息06 - 物体休眠与休眠事件详解(Cannon.js)05-碰撞与碰撞组04 - 弹性与接触材质详解03 - Cannon 材质与摩擦系数设置02 - Cannon 引擎基础碰撞讲解01 - Cannon.js 引擎的用途和基本使用一款减轻前端图片命名工作量的图片转换器总结:一个双非大学生的两年,是怎么过来的?数学公式Input-输入框组件实现详解用HTML5实现实时ASCII艺术摄像头object-fit: contain - CSS 属性详解GSAP (GreenSock Animation Platform) 动画库学习指南Webview通信系统学习指南实现手势操控3D粒子动画?太好玩了!东田数码科技前端面试前端性能优化面试回答技巧(一)React与Vue表单的对比差异融山科技前端面经·React的入门学习(一)九方前端面试JavaScript 核心:数组/字符串 API 精要指南JavaScript的常用数组API原理解析前端练习小网站-新手突破之路前端の骚操作代码合集 (二)| 让你的网页变得有趣前端Threejs入门(五)Vue 3 响应式原理:computed的模板解包机制Vue 监听器 watch 深度解析Axios 深入解析从0到1配置vue项目跟git仓库连接!前端Three.js入门(四)你懂keep-alive吗?见过Vue的小区保安吗?前端Three.js入门(三)前端Three.js入门(二)前端Three.js入门(一)-Three的第一个简单的页面 Git 大冒险:解锁代码管理的秘密武器如何将网站加载速度提升50%?前端性能优化全攻略前端の骚操作代码合集 | 让你的网页充满恶趣味进击蓝桥杯!2025web前端HTML5uniapp-页面生命周期
08刚体约束 Constraint 作者: 前端AC | 原文: https://juejin.cn/post/7530180210872811570 刚体约束 Constraint 本节目标 学习如何使用 cannones 的约束(Constraint)系统,让多个刚体之间具有物理连接,如铰...

08-刚体约束 Constraint

作者: 前端AC | 原文: https://juejin.cn/post/7530180210872811570

刚体约束 Constraint

本节目标

学习如何使用 cannon-es 的约束(Constraint)系统,让多个刚体之间具有物理连接,如铰链、点对点连接等。


基础知识讲解

Cannon.js 中的约束用于在两个刚体之间建立某种规则限制,使它们表现出类似于物理连接(链条、铰链、弹簧等)的行为。

常见约束类型

约束类型描述
PointToPointConstraint点对点连接(类似绳子连接两点)
HingeConstraint铰链连接(门的转动效果)
LockConstraint锁定两个刚体之间的所有自由度
DistanceConstraint固定两个点的距离(距离保持不变)

示例:点对点约束连接两个小球

我们将创建两个小球,并使用 PointToPointConstraint 将它们连接在一起,实现“弹簧绳索”的效果。


示例代码(Vue3 + cannon-es)

vue复制编辑<!-- App.vue -->
<template>
  <canvas ref="canvasRef"></canvas>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import * as THREE from 'three'
import * as CANNON from 'cannon-es'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

const canvasRef = ref()

onMounted(() => {
  // 创建 Three.js 场景
  const scene = new THREE.Scene()
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
  camera.position.set(0, 5, 15)

  const renderer = new THREE.WebGLRenderer({ canvas: canvasRef.value })
  renderer.setSize(window.innerWidth, window.innerHeight)

  const controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true

  // 添加光源
  const light = new THREE.DirectionalLight(0xffffff, 1)
  light.position.set(5, 10, 5)
  scene.add(light)

  // 初始化物理世界
  const world = new CANNON.World()
  world.gravity.set(0, -9.82, 0)

  // 创建地面
  const groundBody = new CANNON.Body({
    mass: 0,
    shape: new CANNON.Plane()
  })
  groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0)
  world.addBody(groundBody)

  const ground = new THREE.Mesh(
    new THREE.PlaneGeometry(20, 20),
    new THREE.MeshStandardMaterial({ color: 0x999999, side: THREE.DoubleSide })
  )
  ground.rotation.x = -Math.PI / 2
  scene.add(ground)

  // 创建两个球体
  const sphereGeo = new THREE.SphereGeometry(0.5, 32, 32)
  const sphereMat = new THREE.MeshStandardMaterial({ color: 0x00aaff })

  const createSphere = (x, y) => {
    const mesh = new THREE.Mesh(sphereGeo, sphereMat)
    mesh.position.set(x, y, 0)
    scene.add(mesh)

    const body = new CANNON.Body({
      mass: 1,
      shape: new CANNON.Sphere(0.5),
      position: new CANNON.Vec3(x, y, 0)
    })
    world.addBody(body)

    return { mesh, body }
  }

  const ballA = createSphere(-2, 5)
  const ballB = createSphere(2, 5)

  // 添加点对点约束(连接 ballA 和 ballB)
  const constraint = new CANNON.PointToPointConstraint(
    ballA.body, new CANNON.Vec3(0.5, 0, 0),
    ballB.body, new CANNON.Vec3(-0.5, 0, 0)
  )
  world.addConstraint(constraint)

  // 动画循环
  const clock = new THREE.Clock()
  function animate() {
    requestAnimationFrame(animate)

    const delta = clock.getDelta()
    world.step(1 / 60, delta)

    // 同步位置
    [ballA, ballB].forEach(({ mesh, body }) => {
      mesh.position.copy(body.position)
      mesh.quaternion.copy(body.quaternion)
    })

    controls.update()
    renderer.render(scene, camera)
  }

  animate()
})
</script>

2025-07-23T16_13_19.635Z-496341.gif
2025-07-23T16_13_19.635Z-496341.gif

重点解释

代码片段解释
PointToPointConstraint将两个球体通过世界坐标系中的特定点连接起来,模拟绳索连接的效果。
new CANNON.Vec3(0.5, 0, 0)约束在 ballA 的局部空间的连接点
new CANNON.Vec3(-0.5, 0, 0)约束在 ballB 的局部空间的连接点
world.addConstraint(...)将该约束注册到物理世界中

你可以尝试的拓展

  • 使用 DistanceConstraint 来实现固定距离效果
  • 将其中一个球体 mass: 0 变为固定点
  • 尝试加入多个球体,实现链条式连接(类似吊桥)

总结

  • 刚体约束是 Cannon.js 中实现刚体间连接的重要方式
  • 本节展示了点对点约束的用法
  • 可以用来实现链条、吊桥、布料物理等效果