材质 × 碰撞:Threejs 物理引擎的双重魔法

材质

在物理引擎中,材质(Material)用于描述物体的物理属性,例如摩擦力、弹性等。

js 复制代码
const material = new CANNON.Material("materialName");

CANNON.Material: 物理材质,用于模拟物体之间的摩擦力、弹性等物理属性。

materialName: 材质的名称,用于标识材质。

摩擦

摩擦力是物体在接触时产生的阻力,可以模拟物体之间的摩擦力。

js 复制代码
const material = new CANNON.Material("materialName");
material.friction = 0.5;

friction: 摩擦力,取值范围为 0 到 1,值越大,摩擦力越大。

js 复制代码
//平面和立方体同样的摩擦系数
const physicsMaterial = new CANNON.Material("physicsMaterial");
//设置摩擦力
physicsMaterial.friction = 0.5;

const planeMaterial = new CANNON.Material("planeMaterial");
//设置摩擦力
planeMaterial.friction = 0.5;

const planeBody = new CANNON.Body({
  mass: 0,
  shape: new CANNON.Plane(),
  material: planeMaterial,
});

const boxBody = new CANNON.Body({
  mass: 1,
  shape: new CANNON.Box(new CANNON.Vec3(1, 1, 1)),
  material: physicsMaterial,
});

反弹

弹性是物体在碰撞时产生的反弹力,可以模拟物体之间的弹性。

js 复制代码
const material = new CANNON.Material("materialName");
material.restitution = 0.5;

restitution: 弹性,取值范围为 0 到 1,值越大,弹性越大。

js 复制代码
//平面和立方体同样的弹性系数
const physicsMaterial = new CANNON.Material("physicsMaterial");
//设置弹性
physicsMaterial.restitution = 1;

const planeMaterial = new CANNON.Material("planeMaterial");
//设置弹性
planeMaterial.restitution = 1;

const planeBody = new CANNON.Body({
  mass: 0,
  shape: new CANNON.Plane(),
  material: planeMaterial,
});

const boxBody = new CANNON.Body({
  mass: 1,
  shape: new CANNON.Box(new CANNON.Vec3(1, 1, 1)),
  material: physicsMaterial,
});

接触材质

接触材质用于描述物体之间的接触属性,例如摩擦力、弹性等。

js 复制代码
const physicsMaterial = new CANNON.Material("physicsMaterial");
const planeMaterial = new CANNON.Material("planeMaterial");

const contactMaterial = new CANNON.ContactMaterial(physicsMaterial, planeMaterial, {
  friction: 0.5,
  restitution: 0.5,
});
world.addContactMaterial(contactMaterial);

ContactMaterial(): 接触材质,用于描述物体之间的接触属性。

  • 第一个参数:第一个物体的材质。
  • 第二个参数:第二个物体的材质。
  • 第三个参数:一个对象,包含摩擦力、弹性等属性。

world.addContactMaterial(): 将接触材质添加到物理世界中。

注意: 物体设置的材质效果会优先覆盖接触材质的效果。

碰撞

碰撞是物体在接触时产生的力,可以模拟物体之间的碰撞。

js 复制代码
//创建物理立方体
const boxBody = new CANNON.Body({
  mass: 1,
  shape: new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5)),
  position: new CANNON.Vec3(-2, 0.5, 0),
  material: physicsMaterial,
});
//创建物理球体
const sphereBody = new CANNON.Body({
  mass: 1,
  shape: new CANNON.Sphere(0.5),
  position: new CANNON.Vec3(0, 0.5, 0),
  material: physicsMaterial,
});
//创建物理圆柱体
const cylinderBody = new CANNON.Body({
  mass: 1,
  shape: new CANNON.Cylinder(0.5, 0.5, 1, 32),
  position: new CANNON.Vec3(2, 0.5, 0),
  material: physicsMaterial,
});

world.add(boxBody);
world.add(sphereBody);
world.add(cylinderBody);

//设置立方体初速度
boxBody.velocity.set(2, 0, 0);

CANNON.Box(): 创建一个立方体形状。

CANNON.Sphere(): 创建一个球体形状。

CANNON.Cylinder(): 创建一个圆柱体形状。

velocity: 设置物体的初速度。

碰撞组

碰撞组用于描述物体之间的碰撞关系,例如物体之间的碰撞是否产生效果。

js 复制代码
//设置碰撞组,立方体可以和球体、圆柱体碰撞,球体可以和立方体碰撞,圆柱体可以和立方体碰撞
groundBody.collisionFilterGroup = 1;
boxBody.collisionFilterGroup = 2;
sphereBody.collisionFilterGroup = 4;
cylinderBody.collisionFilterGroup = 8;
groundBody.collisionFilterMask = 2 | 4 | 8;
boxBody.collisionFilterMask = 1 | 4 | 8;
sphereBody.collisionFilterMask = 1 | 2;
cylinderBody.collisionFilterMask = 1 | 2;

//第二种写法
const GROUP1 = 1;
const GROUP2 = 2;
const GROUP3 = 4;
const GROUP4 = 8;

//地面
const groundBody = new CANNON.Body({
  mass: 0,
  shape: new CANNON.Plane(),
  collisionFilterGroup: GROUP1,
  collisionFilterMask: GROUP2 | GROUP3 | GROUP4,
});

//立方体
const boxBody = new CANNON.Body({
  mass: 1,
  shape: new CANNON.Box(new CANNON.Vec3(1, 1, 1)),
  collisionFilterGroup: GROUP2,
  collisionFilterMask: GROUP1 | GROUP3 | GROUP4,
});

//球体
const sphereBody = new CANNON.Body({
  mass: 1,
  shape: new CANNON.Sphere(1),
  collisionFilterGroup: GROUP3,
  collisionFilterMask: GROUP1 | GROUP2,
});

//圆柱体
const cylinderBody = new CANNON.Body({
  mass: 1,
  shape: new CANNON.Cylinder(1, 1, 1, 32),
  collisionFilterGroup: GROUP4,
  collisionFilterMask: GROUP1 | GROUP2,
});

collisionFilterGroup: 碰撞组,用于描述物体之间的碰撞关系。

collisionFilterMask: 碰撞掩码,用于描述物体之间的碰撞关系。

注意: 碰撞组与碰撞掩码的值是 2 的幂,可以通过位运算符进行组合。所以这里的四组碰撞组分别是 1、2、4、8。

碰撞事件

碰撞事件用于描述物体之间的碰撞,例如碰撞时的位置、速度等。

js 复制代码
boxBody.addEventListener("collide", (e) => {
  console.log("碰撞事件", e);
  console.log("撞击速度", e.contact.getImpactVelocityAlongNormal());
});

addEventListener(): 添加碰撞事件监听器。

  • collide:碰撞事件。

e: 碰撞事件对象。

  • contact:碰撞接触对象。
  • body:碰撞物体对象。
  • target:碰撞目标对象。

getImpactVelocityAlongNormal(): 获取撞击速度。

书洞笔记

相关推荐
酒尘&4 小时前
JS数组不止Array!索引集合类全面解析
开发语言·前端·javascript·学习·js
学历真的很重要4 小时前
VsCode+Roo Code+Gemini 2.5 Pro+Gemini Balance AI辅助编程环境搭建(理论上通过多个Api Key负载均衡达到无限免费Gemini 2.5 Pro)
前端·人工智能·vscode·后端·语言模型·负载均衡·ai编程
用户47949283569155 小时前
"讲讲原型链" —— 面试官最爱问的 JavaScript 基础
前端·javascript·面试
用户47949283569155 小时前
2025 年 TC39 都在忙什么?Import Bytes、Iterator Chunking 来了
前端·javascript·面试
大怪v7 小时前
【Virtual World 04】我们的目标,无限宇宙!!
前端·javascript·代码规范
狂炫冰美式7 小时前
不谈技术,搞点文化 🧀 —— 从复活一句明代残诗破局产品迭代
前端·人工智能·后端
xw58 小时前
npm几个实用命令
前端·npm
!win !8 小时前
npm几个实用命令
前端·npm
代码狂想家8 小时前
使用openEuler从零构建用户管理系统Web应用平台
前端
dorisrv9 小时前
优雅的React表单状态管理
前端