Three.js中实现一个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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!