本文目录
- 前言
- 1、Particle
- 2、前置代码准备
- 2.1 代码
- 2.2 效果
- 3、使用距离约束模拟布料
- 3.1 代码
- 3.2 效果
前言
在现代
Web
开发中,实现逼真的物理效果对于提升用户体验至关重要。Cannon-es.js
,作为Cannon.js
的ES6
模块版本,凭借其轻量级、高性能和易于集成的特点,在WebGL
环境中进行物理模拟时备受青睐。本文将深入探讨Cannon-es.js
在模拟物理效果方面的应用,包括Particle
(粒子)的基本使用、前置代码准备,以及如何使用距离约束来模拟布料效果。
粒子系统在游戏开发、动画制作以及物理模拟等领域有着广泛的应用。通过Cannon-es.js
,我们可以轻松创建和管理粒子,实现各种复杂的物理效果。此外,距离约束作为一种强大的物理约束类型,允许我们模拟物体之间的连接关系,这在模拟布料、绳索等柔性物体时尤为有用。
在接下来的内容中,我们将详细介绍如何准备前置代码,如何使用Cannon-es.js
创建粒子,并通过距离约束来模拟布料效果。希望通过本文的探讨,读者能够掌握Cannon-es.js
在物理模拟方面的基本技巧,并在自己的项目中实现更加复杂和逼真的物理效果。
1、Particle
在cannon-es
(一个轻量级的JavaScript
物理引擎,用于处理刚体动力学模拟)中,Particle
(粒子)并不是传统意义上的三维几何体(如球体、立方体等),而是一个没有形状、大小或旋转属性的质量点。粒子主要用于模拟点质量的行为,如重力作用下的自由落体、碰撞检测中的接触点,或者作为更复杂刚体的一部分(例如,通过约束将多个粒子连接在一起以形成软体物理效果)。
Particle
在cannon-es
中是一个特殊的Body
类型,它只具有位置(position
)、速度(velocity
)和力(force
)等属性,而没有形状(shape
)和惯性(inertia
)等刚体通常具有的属性。由于粒子没有形状,因此它们不会直接参与碰撞检测中的边界计算;相反,它们通常通过与其他粒子或刚体的接触点来间接参与碰撞。
在cannon-es
中创建一个Particle
通常涉及以下步骤:
- 创建一个
CANNON.Body
实例,但将其形状(shape
)属性设置为null
或省略(因为粒子没有形状)。 - 设置粒子的质量(
mass
)。 - (可选)设置粒子的初始位置(
position
)和速度(velocity
)。
2、前置代码准备
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 rows = 15
const cols = 15
const sphereGeometry = new THREE.SphereGeometry(0.2, 16, 16)
const sphereMaterial = new THREE.MeshBasicMaterial({color: 0xff0000})
const particleShape = new CANNON.Particle()
let bodies = {}
for(let i = 0; i < cols; i++) {
for(let j = 0; j < rows; j++) {
// 物理世界
const particleBody = new CANNON.Body({
mass: 0.5,
position: new CANNON.Vec3(i - cols * 0.5, 10, j - rows * 0.5),
shape: particleShape
})
bodies[`${i}-${j}`] = particleBody
physicsWorld.addBody(particleBody)
phyMeshes.push(particleBody)
// 渲染世界
const sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial)
sphereMesh.position.set(i - cols * 0.5, 10, j - rows * 0.5)
meshes.push(sphereMesh)
scene.add(sphereMesh)
}
}
const axesHelper = new THREE.AxesHelper(30);
scene.add(axesHelper);
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 代码
在上面的基础添加距离约束代码:
for(let i = 0; i < cols; i++) {
for(let j = 0; j < rows; j++) {
const body = bodies[`${i}-${j}`]
if (i > 0) {
const body2 = bodies[`${i - 1}-${j}`]
const constraint = new CANNON.DistanceConstraint(body, body2, 0.4)
physicsWorld.addConstraint(constraint)
}
if (j > 0) {
const body2 = bodies[`${i}-${j - 1}`]
const constraint = new CANNON.DistanceConstraint(body, body2, 0.4)
physicsWorld.addConstraint(constraint)
}
}
}
3.2 效果
在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。