Three.js中实现一个OBBHelper

three,js,实现,一个,obbhelper · 浏览次数 : 314

小编点评

代码解释如下: 1.导入了所需的 Three.js 模块和类。 2.创建 OBBHelper 类继承自 LineSegments 类,因此它是一个线段对象。 3.构造函数接收三个参数:obb、object 和 color。 4.创建一个 indices 数组,其中包含了边界框的顶点索引。 5.使用 geometry.setIndex 方法将索引数据分配给几何体的索引属性。 6.使用 geometry.setAttribute方法将顶点位置数据分配给几何体的位置属性。 7.调用父类 LineSegments 的构造函数,传递几何体和材质作为参数,创建一个线段对象。 8.设置 OBBHelper 对象的属性,包括 obb、object 和 type。 9.在 updateMatrixWorld 方法中,更新辅助对象的世界矩阵。首先,将上一次的世界矩阵的逆矩阵应用于 obb 对象,然后将当前的世界矩阵应用于 obb 对象。 10.根据 obb 对象的属性计算出边界框的顶点位置,并更新几何体的位置属性。 11.最后,调用父类的 updateMatrixWorld 方法,更新辅助对象的世界矩阵。 代码中使用了 BufferGeometry 和 Vector3 类来存储几何数据,并使用了 geometry.setIndex 和 geometry.setAttribute 方法来设置顶点位置。最后,使用 updateMatrixWorld 方法来更新辅助对象的的世界矩阵。 通过使用 OBBHelper 类,可以创建一个辅助对象来显示一个方向包围盒的边界框,并将其添加到场景中以进行渲染和显示。

正文

1. 引言

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

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

两者如下图所示:

QQ截图20230922001643

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对象的边界框。

代码中首先导入了一些依赖的模块,包括LineSegmentsLineBasicMaterialBufferAttributeFloat32BufferAttributeBufferGeometry

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方法,用于释放资源,包括释放geometrymaterial对象。

最后通过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)的边界框。以下是代码的解释:

  1. 导入了所需的 Three.js 模块和类。这些模块和类包括 Vector3LineSegmentsLineBasicMaterialBufferAttributeFloat32BufferAttributeBufferGeometry

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

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

  4. 创建一个 indices 数组,其中包含了边界框的顶点索引。这些索引指定了边界框的边的连接关系。

  5. 创建一个 positions 数组,其中包含了边界框的顶点位置。这些位置定义了边界框的形状。

  6. 创建一个 BufferGeometry 对象,用于存储几何数据。

  7. 使用 geometry.setIndex 方法将索引数据分配给几何体的索引属性。

  8. 使用 geometry.setAttribute 方法将顶点位置数据分配给几何体的位置属性。

  9. 调用父类 LineSegments 的构造函数,传递几何体和材质作为参数,创建一个线段对象。

  10. 设置 OBBHelper 对象的属性,包括 obbobjecttype

  11. updateMatrixWorld 方法中,更新辅助对象的世界矩阵。首先,将上一次的世界矩阵的逆矩阵应用于 obb 对象,然后将当前的世界矩阵应用于 obb 对象。接着,根据 obb 对象的属性计算出边界框的顶点位置,并更新几何体的位置属性。

  12. 最后,调用父类的 updateMatrixWorld 方法,更新辅助对象的世界矩阵。

  13. dispose 方法用于释放几何体和材质的内存。

  14. 导出 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的实现 - 掘金 (juejin.cn)

[6] 113 Three.js的obb (OrientedboundingBox)方向包围盒的使用_暮志未晚Webgl的博客-CSDN博客

与Three.js中实现一个OBBHelper相似的内容:

Three.js中实现一个OBBHelper

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

Three.js中实现碰撞检测

本文就如何在Three.js中进行碰撞检测进行记述

Three.js中实现对InstanceMesh的碰撞检测

1. 概述 之前的文章提到,在Three.js中使用InstanceMesh来实现性能优化,可以实现单个Mesh的拾取功能 那,能不能实现碰撞检测呢?肯定是可以的,不过Three.js中并没有直接的API可以实现对InstanceMesh的碰撞检测,需要手动实现 回顾本文的描述的Three.js的场

Three.js使用InstancedMesh实现性能优化

本文记述在three.js中使用InstancedMesh来实现绘制大量几何体的性能优化

第135篇:Three.js基础入门

好家伙,这东西太帅了,我要学会 先放张帅图(都是用three.js做出来的,这我学习动力直接拉满) 还有另外一个 Junni is... 帧数太高,录不了 开始学习 官方文档 1.Three.js是什么? Three.js是一款运行在浏览器中的 3D 引擎(基于WebGL的API的封装),你可以用它

three.js高性能渲染室外场景

大家好,本文在相关文章的基础上,使用three.js渲染了高性能的室外场景,在移动端也有较好的性能,并给出了代码,分析了关键点,感谢大家~ 关键词:three.js、Web3D、WebGL、室外场景、Instanced Draw、大场景、LOD、Frustum Cull、优化、开源 代码:Githu

three.js实现相机碰撞,相机不穿墙壁、物体

大家好,本文实现了相机碰撞检测,使相机不穿墙壁、物体,并给出了思路和代码,感谢大家~ 关键词:数字孪生、three.js、Web3D、WebGL、相机碰撞、游戏相机 我正在承接Web3D数字孪生项目,具体介绍可看承接各种Web3D业务 目录实现原理参考资料 实现前: 移动第三人称相机时,相机可能会穿

基于 Three.js 的 3D 模型加载优化

作为一个3D的项目,从用户打开页面到最终模型的渲染加载的时间也会比普通的H5项目要更长一些,从而造成大量的用户流失。为了提升首屏加载的转化率,需要尽可能的降低loading的时间。这里就分享一些我们在模型加载优化方面的心得。

如何使用webgl(three.js)实现煤矿隧道、井下人员定位、掘进面、纵采面可视化解决方案——第十九课(一)

three.js、webgl、3D煤矿隧道、三维井下人员定位、掘进面三维可视化、纵采面可视化、采集面可视化展示、设备检测、数字孪生、物联网3D、3d建筑、3d库房,bim管理系统

Three.js的基础使用

本文描述Three.js的基础使用与搭建一个场景