Three.js中实现一个OBBHelper实例详解

 更新时间:2023年09月22日 08:54:35   作者:当时明月在曾照彩云归  
这篇文章主要介绍了Three.js中实现一个OBBHelper,本文参考Box3Helper源码,并写出一个OBBHelper,本文结合实例代码给大家介绍的非常详细,需要的朋友可以参考下

本文参考Box3Helper源码,并写出一个OBBHelper

1. 引言

Three.js中,Box3对象指的是AABB式的包围盒,这种包围盒会随物体的旋转而变换大小,精度较差

Three.js中还有OBB对象,这是一种能表现物体主要特征的、不随物体的旋转而变换大小的包围盒

两者如下图所示:

Three.js中虽然有OBB,却没有OBB Helper,即OBB包围盒线框对象

本文参考Box3Helper源码,并写出一个OBBHelper

2. Box3Helper

以下是Three.js源码中的Box3Helper:

import { LineSegments } from '../objects/LineSegments.js';
import { LineBasicMaterial } from '../materials/LineBasicMaterial.js';
import { BufferAttribute, Float32BufferAttribute } from '../core/BufferAttribute.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
class Box3Helper extends LineSegments {
	constructor( box, color = 0xffff00 ) {
		const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
		const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];
		const geometry = new BufferGeometry();
		geometry.setIndex( new BufferAttribute( indices, 1 ) );
		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
		this.box = box;
		this.type = 'Box3Helper';
		this.geometry.computeBoundingSphere();
	}
	updateMatrixWorld( force ) {
		const box = this.box;
		if ( box.isEmpty() ) return;
		box.getCenter( this.position );
		box.getSize( this.scale );
		this.scale.multiplyScalar( 0.5 );
		super.updateMatrixWorld( force );
	}
	dispose() {
		this.geometry.dispose();
		this.material.dispose();
	}
}
export { Box3Helper };
 

这段代码是一个名为 Box3Helper 的类的定义,它继承自 LineSegments 类。 Box3Helper 类用于创建一个辅助框,用来可视化 Box3 对象的边界框。

代码中首先导入了一些依赖的模块,包括 LineSegments 、 LineBasicMaterial 、 BufferAttribute 、 Float32BufferAttribute 和 BufferGeometry 。

在 Box3Helper 类的构造函数中,首先创建了一个表示边界框的索引数组 indices ,然后创建了一个表示边界框的顶点坐标数组 positions 。

接下来,创建了一个 BufferGeometry 对象,并使用 indices 数组创建了一个 BufferAttribute 对象来表示索引,使用 positions 数组创建了一个 Float32BufferAttribute 对象来表示顶点坐标。然后将这两个属性设置到 geometry 对象中。

然后调用父类 LineSegments 的构造函数,传入 geometry 和一个 LineBasicMaterial 对象作为参数,来创建一个可视化边界框的线段对象。

接着,将传入构造函数的 box 参数赋值给 this.box 属性。

然后设置 this.type 属性为 'Box3Helper' 。

最后调用 geometry 对象的 computeBoundingSphere 方法来计算边界球。

Box3Helper 类还定义了一个 updateMatrixWorld 方法,用于更新辅助框的世界矩阵。在该方法中,首先获取 this.box 的中心点和尺寸,然后根据尺寸缩放辅助框的比例,并调用父类的 updateMatrixWorld 方法来更新世界矩阵。

最后,定义了一个 dispose 方法,用于释放资源,包括释放 geometry 和 material 对象。

最后通过 export 语句将 Box3Helper 类导出,以便在其他地方使用。

3. OBBHelper

参考上面的代码。给出OBBHelper的代码如下:

import {
	Vector3, LineSegments, LineBasicMaterial,
	BufferAttribute, Float32BufferAttribute, BufferGeometry
} from 'three';
class OBBHelper extends LineSegments {
	constructor(obb, object, color = 0xffff00) {
		const indices = new Uint16Array([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7, 0, 2, 1, 3, 4, 6, 5, 7]);
		const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];
		const geometry = new BufferGeometry();
		geometry.setIndex(new BufferAttribute(indices, 1));
		geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
		super(geometry, new LineBasicMaterial({ color: color, toneMapped: false }));
		this.obb = obb;
		this.object = object;
		this.type = 'OBBHelper';
		this.lastMatrix4 = object.matrixWorld.clone();
	}
	updateMatrixWorld(force) {
		this.obb.applyMatrix4(this.lastMatrix4.invert())
		this.obb.applyMatrix4(this.object.matrixWorld);
		this.lastMatrix4 = this.object.matrixWorld.clone();
		const positions = this.geometry.attributes.position.array;
		const halfSize = this.obb.halfSize;
		const center = this.obb.center;
		const rotation = this.obb.rotation;
		const corners = [];
		for (let i = 0; i < 8; i++) {
			const corner = new Vector3();
			corner.x = (i & 1) ? center.x + halfSize.x : center.x - halfSize.x;
			corner.y = (i & 2) ? center.y + halfSize.y : center.y - halfSize.y;
			corner.z = (i & 4) ? center.z + halfSize.z : center.z - halfSize.z;
			corner.applyMatrix3(rotation);
			corners.push(corner);
		}
		for (let i = 0; i < corners.length; i++) {
			const corner = corners[i];
			positions[i * 3] = corner.x;
			positions[i * 3 + 1] = corner.y;
			positions[i * 3 + 2] = corner.z;
		}
		this.geometry.attributes.position.needsUpdate = true;
		super.updateMatrixWorld(force);
	}
	dispose() {
		this.geometry.dispose();
		this.material.dispose();
	}
}
export { OBBHelper };

这段代码是一个自定义的 OBBHelper 类,用于创建一个辅助对象来显示一个方向包围盒(OBB)的边界框。以下是代码的解释:

导入了所需的 Three.js 模块和类。这些模块和类包括 Vector3 、 LineSegments 、 LineBasicMaterial 、 BufferAttribute 、 Float32BufferAttribute 和 BufferGeometry 。

OBBHelper 类继承自 LineSegments 类,因此它是一个线段对象。

OBBHelper 构造函数接收三个参数: obb 、 object 和 color 。 obb 是一个方向包围盒对象, object 是一个 Three.js 对象, color 是边界框的颜色,默认为黄色(0xffff00)。

  • 创建一个 indices 数组,其中包含了边界框的顶点索引。这些索引指定了边界框的边的连接关系。
  • 创建一个 positions 数组,其中包含了边界框的顶点位置。这些位置定义了边界框的形状。
  • 创建一个 BufferGeometry 对象,用于存储几何数据。
  • 使用 geometry.setIndex 方法将索引数据分配给几何体的索引属性。
  • 使用 geometry.setAttribute 方法将顶点位置数据分配给几何体的位置属性。
  • 调用父类 LineSegments 的构造函数,传递几何体和材质作为参数,创建一个线段对象。
  • 设置 OBBHelper 对象的属性,包括 obb 、 object 和 type 。
  • 在 updateMatrixWorld 方法中,更新辅助对象的世界矩阵。首先,将上一次的世界矩阵的逆矩阵应用于 obb 对象,然后将当前的世界矩阵应用于 obb 对象。接着,根据 obb 对象的属性计算出边界框的顶点位置,并更新几何体的位置属性。
  • 最后,调用父类的 updateMatrixWorld 方法,更新辅助对象的世界矩阵。
  • dispose 方法用于释放几何体和材质的内存。
  • 导出 OBBHelper 类供其他模块使用。

通过使用这个 OBBHelper 类,可以创建一个辅助对象来显示一个方向包围盒的边界框,并将其添加到场景中以进行渲染和显示。

实现的效果如下(黄色为Box3Helper,红色为OBBHelper):

4. 参考资料

[1] OBB – three.js docs (three3d.cn)

[2] three.js/src/helpers/Box3Helper.js at master · mrdoob/three.js (github.com)

[3] three.js examples (three3d.cn)

[4] three.js/examples/jsm/math/OBB.js at master · mrdoob/three.js (github.com)

[5] BufferGeometry.boundingBox的应用:BoxHelper的实现 

[6] 113 Three.js的obb (OrientedboundingBox)方向包围盒的使用

到此这篇关于Three.js中实现一个OBBHelper的文章就介绍到这了,更多相关Three.js实现OBBHelper内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 微信小程序去除左上角返回键的实现方法

    微信小程序去除左上角返回键的实现方法

    这篇文章主要介绍了微信小程序去除左上角返回键的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 基于pdf.js实现文本划词高亮效果

    基于pdf.js实现文本划词高亮效果

    最近有一个需求,需要对于pdf文本进行操作,对接ai大模型对pdf文档进行高效解读,其中一个功能就是对于pdf的文本进行划词高亮,用户可进行阅读标记,本文给大家介绍了如何基于pdf.js实现文本划词高亮效果,需要的朋友可以参考下
    2024-05-05
  • JS带你深入领略Proxy的世界

    JS带你深入领略Proxy的世界

    Proxy是es2015 标准规范加入的语法,很可能你只是听说过,但并没有用过,毕竟考虑到兼容的问题,不能轻易地使用Proxy特性。但现在随着各个浏览器的更新迭代,Proxy的支持度也越来越高:而且使用Proxy进行代理和劫持,也渐渐成为了趋势。
    2021-05-05
  • 一个不错的字符串转码解码函数(自写)

    一个不错的字符串转码解码函数(自写)

    一个不错的字符串转码解码函数,自己写的,有需要的朋友可以参考下
    2014-07-07
  • js以对象为索引的关联数组

    js以对象为索引的关联数组

    在代码逻辑中更多的是用关联数组的方式。但即使是这样我们也很少使用对象类型作为键值对的键名。
    2010-07-07
  • JavaScript高级程序设计 读书笔记之十一 内置对象Global

    JavaScript高级程序设计 读书笔记之十一 内置对象Global

    由ECMAScript实现提供的、独立于宿主环境的所有对象,在ECMAScript程序开始执行时出现
    2012-03-03
  • 微信浏览器左上角返回按钮监听的实现

    微信浏览器左上角返回按钮监听的实现

    这篇文章主要介绍了微信浏览器左上角返回按钮监听的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • js 利用image对象实现图片的预加载提高访问速度

    js 利用image对象实现图片的预加载提高访问速度

    我们来学习一种名为图像预装载(image preloading)的小技巧来提高图像访问速度,一些浏览器试图通过在本地缓存中保存这些图片来解决此问题,感兴趣的朋友可以了解下
    2013-03-03
  • JavaScript游戏之是男人就下100层代码打包

    JavaScript游戏之是男人就下100层代码打包

    不知不觉,就到了11月份了,其实我为啥要写js游戏,觉得游戏更能引起共鸣。11月份开篇之作:是男人就下100层,相信大家都玩过。
    2010-11-11
  • JS中offset和匀速动画详解

    JS中offset和匀速动画详解

    这篇文章主要介绍了JavaScript动画:offset和匀速动画详解(含轮播图的实现),并把实现代码做了分享,有兴趣的朋友参考下。
    2018-02-02

最新评论