使用 THREE.js 进行边界体积碰撞检测

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
简介: 本文介绍如何使用 Three.js 库在边界框和球体之间实现冲突检测。假设在阅读本文之前,您已经先阅读了我们的 3D 碰撞检测介绍性文章,并了解了 Three.js 的基本知识。
推荐:使用 NSDT场景编辑器 快速搭建3D应用场景

使用 Box3 和 Sphere

三.js具有表示数学体积和形状的对象 - 对于3D AABB和边界球体,我们可以使用Box3Sphere对象。实例化后,它们具有可用于针对其他卷进行交集测试的方法。

实例化盒子

要创建 Box3 实例,我们需要提供盒子的下限和上限。通常,我们希望这个AABB被“链接”到我们3D世界中的对象(如角色)。在 Three.js 中,实例具有对象的属性和边界。请记住,为了定义此属性,您需要事先手动调用。GeometryboundingBoxminmaxGeometry.computeBoundingBox

.JS复制到剪贴板

const knot = new THREE.Mesh(
  new THREE.TorusKnotGeometry(0.5, 0.1),
  new MeshNormalMaterial({}),
);
knot.geometry.computeBoundingBox();
const knotBBox = new Box3(
  knot.geometry.boundingBox.min,
  knot.geometry.boundingBox.max,
);

注意:该属性将自身作为引用,而不是 .因此,在计算计算框时,应用于 的任何转换(例如比例、位置等)都将被忽略。boundingBoxGeometryMeshMesh

解决上一个问题的更简单的替代方法是稍后使用 设置这些边界,这将计算尺寸,同时考虑 3D 实体的变换任何子网格Box3.setFromObject

.JS复制到剪贴板

const knot = new THREE.Mesh(
  new THREE.TorusKnotGeometry(0.5, 0.1),
  new MeshNormalMaterial({}),
);
const knotBBox = new Box3(new THREE.Vector3(), new THREE.Vector3());
knotBBox.setFromObject(knot);

实例化球体

实例化 Sphere 对象与此类似。我们需要提供球体的中心和半径,可以将其添加到 中可用的属性中。boundingSphereGeometry

.JS复制到剪贴板

const knot = new THREE.Mesh(
  new THREE.TorusKnotGeometry(0.5, 0.1),
  new MeshNormalMaterial({}),
);
const knotBSphere = new Sphere(
  knot.position,
  knot.geometry.boundingSphere.radius,
);

遗憾的是,没有等效的 Sphere 实例。因此,如果我们应用变换或更改位置 ,我们需要手动更新边界球体。例如:Box3.setFromObjectMesh

.JS复制到剪贴板

knot.scale.set(2, 2, 2);
knotBSphere.radius = knot.geometry.radius * 2;

交叉测试

点与Box3 / Sphere

两者都有一个包含点方法来执行此测试。Box3Sphere

.JS复制到剪贴板

const point = new THREE.Vector3(2, 4, 7);
knotBBox.containsPoint(point);

Box3Box3

Box3.intersectsBox 方法可用于执行此测试。

.JS复制到剪贴板

knotBbox.intersectsBox(otherBox);

注意:这与检查 Box3 是否完全包装另一个的方法不同。Box3.containsBox

SphereSphere

与以前类似的方式,有一个 Sphere.intersectsSphere 方法来执行此测试。

.JS复制到剪贴板

knotBSphere.intersectsSphere(otherSphere);

SphereBox3

不幸的是,这个测试没有在 Three.js 中实现,但我们可以修补 Sphere 以实现 Sphere 与 AABB 交集算法。

.JS复制到剪贴板

// expand THREE.js Sphere to support collision tests vs. Box3
// we are creating a vector outside the method scope to
// avoid spawning a new instance of Vector3 on every check
THREE.Sphere.__closest = new THREE.Vector3();
THREE.Sphere.prototype.intersectsBox = function (box) {
  // get box closest point to sphere center by clamping
  THREE.Sphere.__closest.set(this.center.x, this.center.y, this.center.z);
  THREE.Sphere.__closest.clamp(box.min, box.max);
  const distance = this.center.distanceToSquared(THREE.Sphere.__closest);
  return distance < this.radius * this.radius;
};

演示

我们准备了一些现场演示来演示这些技术,并提供了要检查的源代码。

使用 BoxHelper

作为使用 raw 和 object 的替代方法,Three.js 有一个有用的对象,可以更轻松地处理边界框:BoxHelper(以前已弃用)。此帮助程序获取并为其计算边界框体积(包括其子网格)。这将生成一个表示边界框的新框,该框显示边界框的形状,并且可以传递给前面看到的方法,以便使边界框与 .Box3SphereBoundingBoxHelperMeshMeshsetFromObjectMesh

BoxHelper是处理 Three.js 中边界体积的 3D 碰撞的推荐方法。你会错过球体测试,但权衡是非常值得的。

使用此帮助程序的优点是:

  • 它有一个方法,如果链接的网格旋转或更改其尺寸,它将调整其边界框网格的大小,并更新其位置update()
  • 它在计算边界框的大小时会考虑子网格,因此原始网格及其所有子网格都已包装。
  • 我们可以通过渲染创建的 es 来轻松调试碰撞。默认情况下,它们是使用材质(用于绘制线框样式几何图形的三.js材质)创建的。MeshBoxHelperLineBasicMaterial

主要缺点是它只创建框边界体积,所以如果你需要球体与 AABB 测试,你需要创建自己的对象。Sphere

要使用它,我们需要创建一个新实例并提供几何体和(可选)将用于线框材料的颜色。我们还需要将新创建的对象添加到场景中才能渲染它。我们假设我们的场景变量被调用。BoxHelperthree.jsscene

.JS复制到剪贴板

const knot = new THREE.Mesh(
  new THREE.TorusKnotGeometry(0.5, 0.1),
  new THREE.MeshNormalMaterial({}),
);
const knotBoxHelper = new THREE.BoxHelper(knot, 0x00ff00);
scene.add(knotBoxHelper);

为了也拥有我们的实际边界框,我们创建了一个新对象并使其具有 的形状和位置。Box3Box3BoxHelper

.JS复制到剪贴板

const box3 = new THREE.Box3();
box3.setFromObject(knotBoxHelper);

如果我们更改位置、旋转、缩放等,我们需要调用该方法,以便实例与其链接匹配。我们还需要再次调用才能使 .Meshupdate()BoxHelperMeshsetFromObjectBox3Mesh

.JS复制到剪贴板

knot.position.set(-3, 2, 1);
knot.rotation.x = -Math.PI / 4;
// update the bounding box so it stills wraps the knot
knotBoxHelper.update();
box3.setFromObject(knotBoxHelper);

执行碰撞测试的方式与上一节中解释的方式相同 — 我们使用 Box3 对象的方式与上述相同。

.JS复制到剪贴板

// box vs. box
box3.intersectsBox(otherBox3);
// box vs. point
box3.containsPoint(point.position);

演示

您可以在我们的现场演示页面上查看两个演示。第一个展示了使用 .第二个执行盒与盒测试。BoxHelper


原文链接:https://www.mvrlink.com/bounding-volume-collision-detection-with-threejs/

目录
相关文章
|
6月前
|
JavaScript 算法
原生JS完成“一对一、一对多”矩形DIV碰撞检测、碰撞检查,通过计算接触面积(重叠覆盖面积)大小来判断接触对象DOM
原生JS完成“一对一、一对多”矩形DIV碰撞检测、碰撞检查,通过计算接触面积(重叠覆盖面积)大小来判断接触对象DOM
|
6月前
|
JavaScript 前端开发
JavaScript 中如何检测一个变量是一个 String 类型?
JavaScript 中如何检测一个变量是一个 String 类型?
61 2
|
2月前
|
存储 JavaScript 对象存储
js检测数据类型有那些方法
js检测数据类型有那些方法
137 59
|
2月前
|
编解码 前端开发 JavaScript
javascript检测网页缩放演示代码
javascript检测网页缩放演示代码
|
9天前
|
Web App开发 JavaScript 前端开发
使用 Chrome 浏览器的内存分析工具来检测 JavaScript 中的内存泄漏
【10月更文挑战第25天】利用 Chrome 浏览器的内存分析工具,可以较为准确地检测 JavaScript 中的内存泄漏问题,并帮助我们找出潜在的泄漏点,以便采取相应的解决措施。
83 9
|
9天前
|
监控 JavaScript 前端开发
如何检测和解决 JavaScript 中内存泄漏问题
【10月更文挑战第25天】解决内存泄漏问题需要对代码有深入的理解和细致的排查。同时,不断优化和改进代码的结构和逻辑也是预防内存泄漏的重要措施。
28 6
|
5月前
|
算法 JavaScript 前端开发
在JavaScript中实现基本的碰撞检测算法,我们通常会用到矩形碰撞检测,也就是AABB(Axis-Aligned Bounding Box)碰撞检测
【6月更文挑战第16天】JavaScript中的基本碰撞检测涉及AABB(轴对齐边界框)方法,常用于2D游戏。`Rectangle`类定义了矩形的属性,并包含一个`collidesWith`方法,通过比较边界来检测碰撞。若两矩形无重叠部分,四个条件(关于边界相对位置)均需满足。此基础算法适用于简单场景,复杂情况可能需采用更高级的检测技术或物理引擎库。
89 6
|
22天前
|
存储 JavaScript 前端开发
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
JavaScript 数据类型分为基本数据类型和引用数据类型。基本数据类型(如 string、number 等)具有不可变性,按值访问,存储在栈内存中。引用数据类型(如 Object、Array 等)存储在堆内存中,按引用访问,值是可变的。本文深入探讨了这两种数据类型的特性、存储方式、以及检测数据类型的两种常用方法——typeof 和 instanceof,帮助开发者更好地理解 JavaScript 内存模型和类型检测机制。
48 0
JavaScript 数据类型详解:基本类型与引用类型的区别及其检测方法
|
3月前
|
编解码 JavaScript 前端开发
JS逆向浏览器脱环境专题:事件学习和编写、DOM和BOM结构、指纹验证排查、代理自吐环境通杀环境检测、脱环境框架、脱环境插件解决
JS逆向浏览器脱环境专题:事件学习和编写、DOM和BOM结构、指纹验证排查、代理自吐环境通杀环境检测、脱环境框架、脱环境插件解决
98 1
|
3月前
|
前端开发 JavaScript
Web 前端大揭秘!JS 数据类型检测竟如此震撼,一场惊心动魄的代码探秘之旅等你来!
【8月更文挑战第23天】在Web前端开发中,合理检测数据类型至关重要。JavaScript作为动态类型语言,变量类型可在运行时变化,因此掌握检测技巧十分必要。
34 1