本文目录
- 前言
- 1、cannon-es给物体施加力
- 1.1 前置代码
- 1.2 效果
- 1.3 给小球施加力
- 1. applyForce
- 效果
- 2. applyImpulse
- 效果
- 3. applyLocalImpulse
- 效果
- 4. applyTorque
- 效果
- 区别总结
前言
在三维物理引擎的世界里,Cannon-ES以其轻量级和高效能著称,为开发者提供了强大的工具来模拟现实世界中的物理现象。本指南将带您深入探索Cannon-ES中如何给物体施加不同类型的力,从而控制其动态行为。从基础的applyForce到瞬间的applyImpulse,再到局部坐标系下的applyLocalImpulse,以及改变物体旋转的applyTorque,我们将逐一解析这些方法的用法、效果及其之间的区别。
通过前置代码的搭建,您将能够快速上手并理解每个方法的基本使用方式。随后,我们将通过实际示例展示如何给小球施加不同类型的力,并观察其产生的不同效果。这不仅能帮助您理解物理引擎背后的原理,还能激发您在游戏开发、物理模拟等领域的创造力。
让我们一同踏上这段探索之旅,掌握Cannon-ES中物体动力控制的精髓,为您的项目增添更多生动与真实感。
1、cannon-es给物体施加力
1.1 前置代码
<template>
<canvas ref="cannonDemo" class="cannonDemo">
</canvas>
</template>
<script setup>
import { onMounted, ref } from "vue"
import * as THREE from 'three'
import * as CANNON from 'cannon-es'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
const cannonDemo = ref('null')
onMounted(() => {
const cannonDemoDomWidth = cannonDemo.value.offsetWidth
const cannonDemoDomHeight = cannonDemo.value.offsetHeight
// 创建场景
const scene = new THREE.Scene
// 创建相机
const camera = new THREE.PerspectiveCamera( // 透视相机
45, // 视角 角度数
cannonDemoDomWidth / cannonDemoDomHeight, // 宽高比 占据屏幕
0.1, // 近平面(相机最近能看到物体)
1000, // 远平面(相机最远能看到物体)
)
camera.position.set(0, 2, 30)
// 创建渲染器
const renderer = new THREE.WebGLRenderer({
antialias: true, // 抗锯齿
canvas: cannonDemo.value
})
// 设置设备像素比
renderer.setPixelRatio(window.devicePixelRatio)
// 设置画布尺寸
renderer.setSize(cannonDemoDomWidth, cannonDemoDomHeight)
const light = new THREE.AmbientLight(0x404040, 200); // 柔和的白光
scene.add(light);
let meshes = []
let phyMeshes = []
// 创建物理世界开始
const physicsWorld = new CANNON.World()
// 设置y轴重力
physicsWorld.gravity.set(0, -9.82, 0)
// 创建物理材料
const groundMaterial = new CANNON.Material('groundMaterial')
groundMaterial.friction = 1
groundMaterial.restitution = 1 // 反弹系数
const planeShape = new CANNON.Plane()
// 创建物理地面
const groundBody = new CANNON.Body({
mass: 0, // 为0表示地面不受重力影响
shape: planeShape,
position: new CANNON.Vec3(0, 0, 0),
material: groundMaterial,
})
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0)
physicsWorld.addBody(groundBody)
// 设置球体材质
const sphereMaterial = new CANNON.Material('sphereMaterial')
sphereMaterial.friction = 0 // 摩擦系数
sphereMaterial.restitution = 0 // 反弹系数
// 创建球体刚体
const sphereShape = new CANNON.Sphere(1) // 创建球体形状,并且传递半径跟threejs中的小球半径一致
const sphereBody = new CANNON.Body({
mass: 1,
position: new CANNON.Vec3(0, 1, 0),
material: sphereMaterial,
shape: sphereShape
})
physicsWorld.addBody(sphereBody)
phyMeshes.push(sphereBody)
// 物理世界结束
// 场景世界开始
const axesHelper = new THREE.AxesHelper( 15 );
scene.add( axesHelper );
// 地面
const plane = new THREE.Mesh(
new THREE.PlaneGeometry(30, 30),
new THREE.MeshBasicMaterial({
wireframe: true
})
)
plane.rotation.x = -Math.PI/2
// 添加到场景中
scene.add(plane)
// 小球
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(1, 20, 10),
new THREE.MeshBasicMaterial({
color: 0xff0000,
wireframe: true
})
)
scene.add(sphere)
meshes.push(sphere)
// 场景世界结束
const updatePhysic = () => { // 因为这是实时更新的,所以需要放到渲染循环动画animate函数中
physicsWorld.step(1 / 60)
for (let i = 0; i < phyMeshes.length; i++) {
meshes[i].position.copy(phyMeshes[i].position)
meshes[i].quaternion.copy(phyMeshes[i].quaternion)
}
}
// 控制器
const control = new OrbitControls(camera, renderer.domElement)
// 开启阻尼惯性,默认值为0.05
control.enableDamping = true
// 渲染循环动画
function animate() {
// 在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循环(在大多数屏幕上,刷新率一般是60次/秒)
requestAnimationFrame(animate)
updatePhysic()
// 更新控制器。如果没在动画里加上,那必须在摄像机的变换发生任何手动改变后调用
control.update()
renderer.render(scene, camera)
}
// 执行动画
animate()
})
</script>
<style scoped>
.cannonDemo {
width: 100vw;
height: 100vh;
}
</style>
1.2 效果
可以看到我们的场景中有一个线框小球。
1.3 给小球施加力
在cannon-es这个3D物理引擎中,applyForce、applyImpulse、applyLocalImpulse和applyTorque是用于控制刚体动态行为的重要方法。它们各自具有不同的用途、参数使用方式和效果。以下是这四个方法的详细解释、区别以及参数使用方法的说明:
1. applyForce
-
作用:
applyForce
方法用于在刚体上施加一个持续的力。这个力会按照物理学的原理(F=ma)逐渐改变刚体的速度和运动状态。 -
参数:
- force:一个
CANNON.Vec3
向量,表示要施加的力的大小和方向。 - worldPoint(可选):一个
CANNON.Vec3
向量,表示力作用在刚体上的世界坐标系中的点。如果不提供此参数,则默认作用在刚体的质心上。
- force:一个
-
使用示例:
const force = new CANNON.Vec3(50, 0, 0); // 在X轴上施加一个100单位的力 sphereBody.applyForce(force, new CANNON.Vec3(0, -1, 0)); // 将力作用在刚体的当前位置
力作用在小球的正中心底部,它就会形成回旋向前进
效果
2. applyImpulse
- 作用:
applyImpulse
方法用于在刚体上施加一个瞬间的冲量。这个冲量会直接影响刚体的速度,使其立即获得一个速度增量。 - 参数:
- impulse:一个
CANNON.Vec3
向量,表示要施加的冲量的大小和方向。 - worldPoint(可选):与
applyForce
相同,表示冲量作用在刚体上的世界坐标系中的点。
- impulse:一个
- 使用示例:
const impulse = new CANNON.Vec3(5, 0, 0); // 在x轴上施加一个5单位的冲量 sphereBody.applyImpulse(impulse, sphereBody.position); // 将冲量作用在刚体的当前位置
效果
3. applyLocalImpulse
- 作用:
applyLocalImpulse
方法与applyImpulse
类似,也是用于施加瞬间的冲量,但不同之处在于它接受的是局部坐标系下的冲量向量。 - 参数:
- localImpulse:一个
CANNON.Vec3
向量,表示在刚体局部坐标系中要施加的冲量的大小和方向。 - localPoint(可选):一个
CANNON.Vec3
向量,表示冲量作用在刚体上的局部坐标系中的点。如果不提供此参数,则默认作用在刚体的局部质心上。
- localImpulse:一个
- 使用示例:
const localImpulse = new CANNON.Vec3(0, 0, 9); // 在刚体局部坐标系的Z轴上施加一个9单位的冲量 sphereBody.applyLocalImpulse(localImpulse, new CANNON.Vec3()); // 默认作用在局部质心上
效果
4. applyTorque
- 作用:
applyTorque
方法用于在刚体上施加一个力矩,使其产生旋转。这个力矩会改变刚体的角速度和旋转方向。 - 参数:
- torque:
CANNON.Vec3
,表示要施加的力矩的大小和方向。力矩的方向遵循右手定则,即右手四指从力矩的起点指向终点,大拇指的方向即为力矩的旋转方向。
- torque:
- 使用示例:
const torque = new CANNON.Vec3(0, 0, 100); // 在Z轴上施加一个使刚体绕Z轴旋转的力矩 sphereBody.applyTorque(torque); // 施加力矩
效果
区别总结
方法 | 作用 | 特点 | 参数 |
---|---|---|---|
applyForce | 施加持续的力 | 渐进改变速度 | force (必需),worldPoint (可选) |
applyImpulse | 施加瞬间的冲量 | 立即改变速度 | impulse (必需),worldPoint (可选) |
applyLocalImpulse | 施加瞬间的冲量(局部坐标系) | 立即改变速度,冲量在局部坐标系中定义 | localImpulse (必需),localPoint (可选) |
applyTorque | 施加力矩 | 改变角速度和旋转方向 | torque (必需) |
在使用这些方法时,需要注意以下几点:
- 力的方向和大小、冲量的大小和方向、力矩的大小和方向都是通过
CANNON.Vec3
向量来指定的,该向量包含X、Y、Z三个分量。 - 力的作用点和冲量的作用点可以是刚体上的任意点,但如果不指定,则默认作用在刚体的质心上。对于力矩,它总是绕刚体的质心旋转,因为力矩的作用点默认是质心。
- 施加力、冲量或力矩后,刚体的运动状态会相应地发生变化,包括速度、角速度等。
- 在使用
applyLocalImpulse
时,需要确保提供的冲量向量是在刚体的局部坐标系中定义的。如果刚体发生了旋转,那么局部坐标系也会随之变化。
在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。