Threejs + CannonJS物理引擎 第一个案例教程

Threejs + CannonJS物理引擎

参考资料:Three.js中文网

物理引擎CannonJS简介和引入

JavaScript物理模拟引擎还是比较多的,比如Ammo.js、Physi.js、Cannon.js,这些引擎虽然语法细节有差异,但是在3D应用中开发思路是相似的。

本课程就以Cannon.js为例给大家讲解three.js物理引擎的结合。

github资源cannon.js

github资源cannon.js:https://github.com/schteppe/cannon.js

cannon.js文档:可以在本地静态服务器打开cannon.js\docs\index.html预览Canonjs引擎的文档。

cannon.js案例cannon.js\examples\\demos\目录下可以看到一些cannonjs和three.js结合的一些小例子。

github资源cannon-es

cannon-escannon.js进行了重写,补充支持了ES6和Typescript语法。

不过除了es语法版本问题,也要注意一点就是cannon-es也改变了cannon.js部分API写法,这一点提醒大家,你查看别人文档或代码一定注意,别人用的cannon.js还是cannon-es

github资源cannon-es:https://github.com/dreammonkey/cannon-es

cannon-es在线文档:https://pmndrs.github.io/cannon-es/docs/index.html

cannon-es在线案例:https://pmndrs.github.io/cannon-es/

cannon-es案例cannon-es\examples\目录下可以看到一些cannonjs和three.js结合的一些小例子。

本课程使用cannon-es给大家讲解CannonJS的使用。

cannon-es安装和引入

在工程化开发的时候可以通过npm命令行安装cannon.js模块。

npm install --save cannon-es
// 某个API
import {World, Vec3} from "cannon-es";
// 全部API一次性引入
import * as CANNON from "cannon-es";

咱们课件中是在.html文件中直接引入的cannon-es,实际开发,用上面npm安装方式引入即可。

 <script type="importmap">
    {
			"imports": {
        		"cannon-es": "../cannon-es/dist/cannon-es.js"
			}
		}
	</script>
  <script type="module">
    import * as CANNON from 'cannon-es';
    // 测试是否引入成功
    console.log('CANNON', CANNON.World); 
    
    import { World } from 'cannon-es';
    console.log('World', World);
  </script>

CannonJS自由落体计算

正式使用物理引擎CannonJS与Threejs结合之前,先用CannonJS模拟一个小球自由落体运动的物理计算。

物理引擎概念解释

所谓物理引擎,就是通过代码模拟物理世界。举个简单例子,比如你初高中都学过物理学,其中速度加速度位移都是比较常见的物理量,咱们通过CannonJS等物理引擎,都可以辅助你计算生活中物体的速度位移,比如计算一个小球在地球重力的作用下,下落的速度和位置。

引入物理引擎cannon-es

上节课给大家讲解过,怎么引入物理引擎cannon-es。

import * as CANNON from "cannon-es";

碰撞体Body

通过CANNON.Body类,可以创建一个用于物体物理模拟计算,比如用Body表示一个球、一个箱子、一张桌子,你可以计算Body的位置、速度等物理量。

你可以也把Body称为碰撞体collider。

const body = new CANNON.Body();

设置Body的物理属性

设置Body的一些物理属性,比如质量mass

const body = new CANNON.Body({
    mass: 0.3, // 碰撞体质量0.3kg
});

设置物体body的位置,CannonJS的三维向量Vec3和threejs名称不同,不过使用方式相似。

const body = new CANNON.Body({
    mass: 0.3,
     // 碰撞体的三维空间中位置
    position: new CANNON.Vec3(0, 100, 0)
});

碰撞体Body几何形状

第一次接触Body,你可以类比threejs的Mesh去联想记忆,网格模型表示一个物体,需要通过几何体Geometry定义Mesh的几何外形,对于Body同样道理,你需要设置物体Body的几何形状。

CannonJS定义几何体形状的API有很多种,比如比如长方体Box、球体Sphere等等,本节课先给大家介绍球体Sphere

// 1m半径球体
const bodyShape = new CANNON.Sphere(1);
// 可以把Body称为碰撞体,用来模拟生活中的物体
const body = new CANNON.Body({
    mass: 0.3, 
    position: new CANNON.Vec3(0, 100, 0),
    shape: bodyShape,//碰撞体的几何体形状
});

CANNON.World创建一个物理世界

通过CANNON.World类创建一个物理世界。

// CANNON.World创建物理世界对象
const world = new CANNON.World();

定义物理世界的物理属性,比如设置重力加速度。

重力加速度的属性gravity类似body的位置,是一个三维向量Vec3

重力加速度x、y、z分量值,实际开发根据自己项目和坐标系设置即可,咱们假设小球所在的场景,y轴竖直向上,这样重力就速度就是y方向负方向。

const world = new CANNON.World();
// 设置物理世界重力加速度
world.gravity.set(0, -9.8, 0); //单位:m/s²

.addBody()把物体添加到物理世界

物理球body添加到物理世界中,这样body就会受到物理世界加速度的影响World。

const world = new CANNON.World();
world.addBody(body);

world.step()物理世界更新计算

最后不要忘记周期性执行world.step()方法,world.step()方法第一个参数表示固定时间步长,一般可以设置为1/60秒,用于近似计算。

function render() {
    world.step(1/60);//更新物理计算
    requestAnimationFrame(render);
}
render()
//固定的时间步长1/60秒
const fixedTimeStep = 1/60;
function render() {
    world.step(fixedTimeStep);
}

浏览器控制台查看计算结果

你可以查看物体对象body的位置.position、速度.velocity属性。

function render() {
    console.log('球位置', body.position);
    console.log('球速度', body.velocity);
    console.log('y方向球位置', body.position.y);
    world.step(1/60);//更新物理计算
    requestAnimationFrame(render);
}

浏览器控制辅助开发

除了查看文档,你还可以通过浏览器控制台,查看CannonJS某个类的属性或方法。

Body具有位置.position、重量.mass、几何形状.shapes等属性

const body = new CANNON.Body();
console.log('body', body);
const body = new CANNON.Body({
    mass: 0.3, 
    position: new CANNON.Vec3(0, 100, 0),
    shape: new CANNON.Sphere(1),
});

比如body.position位置属性的属性值是三维向量Vec3,Vec3具有xyz属性和set等多个方法。

const body = new CANNON.Body();
console.log('body.position', body.position);

语法总结:访问或设置Body属性

通过函数选项设置body对象

const body = new CANNON.Body({
    mass: 0.3, 
    position: new CANNON.Vec3(0, 100, 0),
    shape: new CANNON.Sphere(0.1),
});

部分属性也可以直接访问设置。

const body = new CANNON.Body();
body.mass = 0.3;
body.position = new CANNON.Vec3(0, 100, 0);

body没有.shape属性,而是.shapes属性,Body类提供了方法.addShape()设置几何体,执行.addShape()方法会改变.shapes属性。

const body = new CANNON.Body();
body.addShape(new CANNON.Sphere(1));

练习-threejs可视化cannon计算结果

本节课是一个练习题,就是用threejs把cannonjs计算的小球位置可视化表示出来。

  • CannonJS:负责物理计算,比如计算出来一个小球的下落位置
  • three.js:负责可视化渲染,比如用Mesh渲染一个下落的小球视觉效果

一个负责物理模拟计算,一个负责3D场景的渲染

知识点回顾

参考上节课知识点,创建一个body表示小球,与threejs的网格小球mesh对应。

const world = new CANNON.World();
// 设置物理世界重力加速度
world.gravity.set(0, -9.8, 0);

// 物理小球:对应threejs的网格小球
const body = new CANNON.Body({
    mass: 0.3,//碰撞体质量
    shape:new CANNON.Sphere(1),
});
body.position.y = 100;
world.addBody(body);

// 网格小球
const geometry = new THREE.SphereGeometry(1);
const material = new THREE.MeshLambertMaterial({
    color: 0x00ffff,
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = 100;

渲染循环更新小球位置

执行world.step()会更新计算物理小球body的下落位置,这时候如果你想看到threejs小球Mesh下落动画,就需要把body位置同步到mesh上面,非常简单,直接复制即可mesh.position.copy(body.position)

const fixedTimeStep = 1/60;
// 渲染循环
function render() {
    world.step(fixedTimeStep);
    // 渲染循环中,同步物理球body与网格球mesh的位置
    mesh.position.copy(body.position);
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}
render();

调节物理世界加速度

你可以尝试改变物理世界的重力加速度,对比不同加速度,threejs小球Mesh下落动画视觉效果差异。

world.gravity.set(0, -9.8, 0);
world.gravity.set(0, -50, 0);

你实际设置,重力加速度不一定就是设置为9.8,也可以根据需要设置不同的重力加速度大小,开发游戏或元宇宙项目,物理效果追求的是感知正确,不是物理正确,所谓感知正确,就是你的眼睛看着正常就行,并不一定非要与现实100%一致,cannonjs一般就是近似计算位置、速度。当然咱们这节课还没有结合threejs,大家看不到视觉效果,后面咱们都会结合threejs网格Mesh给大家演示。

  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Threejs可视化

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值