本文目录
- 前言
- 最终效果
- 1、Distance Constrait的基本属性和方法
- 1.1 属性
- 1.2 方法
- 2、Distance Constrait的约束详解
- 2.1 前置代码准备
- 2.2 效果
- 3、模拟生成小球撞击
- 3.1 代码
- 3.2 效果
前言
在Cannon-es.js中,DistanceConstraint(距离约束)是一种用于在物理引擎中约束两个刚体之间距离的约束类型。这种约束确保了无论这两个刚体如何移动,它们之间的相对距离都保持不变或者保持在一个指定的范围内。以下是关于DistanceConstraint的详细介绍,包括其属性和方法。
最终效果
1、Distance Constrait的基本属性和方法
1.1 属性
DistanceConstraint的主要属性:
bodyA
:第一个被约束的刚体。在创建DistanceConstraint
时,需要知道这个刚体bodyB
:第二个被约束的刚体。同样,在创建DistanceConstraint
时,也需要指定这个刚体。distance
:要保持的距离。这是两个刚体之间应当保持的恒定距离。如果为定义,它将被设置为刚体A和刚体B之间的当前距离。maxForce
:约束物体应施加的最大力。这是当试图维持制定距离时,约束可以施加在刚体上的最大力量。它有助于防止因约束而导致的刚体行为过于极端。
1.2 方法
虽然DistanceConstraint在Cannon-es.js中可能没有直接暴露太多的方法供调用(因为约束的主要逻辑是内嵌在物理引擎中的),但通常会有一些通用的方法来管理约束,如:
- 启用/禁用:虽然Cannon-es.js可能不直接提供enable或disable方法来针对DistanceConstraint启用或禁用约束,但可以通过将约束从物理世界中移除(通过调用world.removeConstraint(constraint))来间接禁用它,或者通过重新添加到物理世界中来启用它。
2、Distance Constrait的约束详解
2.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, 70)
// 创建渲染器
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 = 0 // 反弹系数
// 创建物理地面
const groundBody = new CANNON.Body({
mass: 0, // 为0表示地面不受重力影响
shape: new CANNON.Box(new CANNON.Vec3(20, 0.05, 20)),
position: new CANNON.Vec3(0, 0, 0),
material: groundMaterial,
})
physicsWorld.addBody(groundBody)
// 设置立方体材质
const sphereMaterial = new CANNON.Material('sphereMaterial')
sphereMaterial.friction = 1 // 摩擦系数
sphereMaterial.restitution = 0 // 反弹系数
const sphereThreeGeometry = new THREE.SphereGeometry( 1, 32, 16 )
const sphereThreeMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000,
})
const sphereShape = new CANNON.Sphere(1)
let previousBody
for (let i = 0; i < 9; i++) {
// 场景世界 创建一个球立方体
const sphereThreeMesh = new THREE.Mesh(
sphereThreeGeometry,
sphereThreeMaterial
)
meshes.push(sphereThreeMesh)
scene.add(sphereThreeMesh)
// 物理世界 创建球刚体
const sphereBody = new CANNON.Body({
mass: i == 0 ? 0 : 1,
position: new CANNON.Vec3(0, 25 - i * 2.2, 0),
material: sphereMaterial,
shape: sphereShape,
type: i == 0 ? CANNON.Body.STATIC : CANNON.Body.DYNAMIC
})
physicsWorld.addBody(sphereBody)
phyMeshes.push(sphereBody)
if (i > 0) {
const constraint = new CANNON.DistanceConstraint(
previousBody,
sphereBody,
2.2
)
physicsWorld.addConstraint(constraint)
}
previousBody = sphereBody
}
// 场景世界开始
const axesHelper = new THREE.AxesHelper(30);
scene.add(axesHelper);
// 地面
const plane = new THREE.Mesh(
new THREE.BoxGeometry(40, 0.1, 40),
new THREE.MeshBasicMaterial({
wireframe: true
})
)
// 添加到场景中
scene.add(plane)
// 场景世界结束
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>
2.2 效果
3、模拟生成小球撞击
3.1 代码
代码:
window.addEventListener('click', () => {
// three.js
const geometry = new THREE.SphereGeometry(1, 32, 16)
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 })
const sphere = new THREE.Mesh(geometry, material)
scene.add(sphere)
meshes.push(sphere)
// cannon-es.js
const sphereBody = new CANNON.Body({
mass: 1,
shape: new CANNON.Sphere(1),
position: new CANNON.Vec3(0, 18, 5), // 初始位置
velocity: new CANNON.Vec3(0,0,-10), // 初始速度
});
phyMeshes.push(sphereBody)
physicsWorld.addBody(sphereBody)
})
3.2 效果
在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。