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

代码中首先导入了一些依赖的模块,包括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的更多相关文章

  1. php中向前台js中传送一个二维数组

    在php中向前台js中传送一个二维数组,并在前台js接收获取其中值的全过程方法: (1),方法说明:现在后台将数组发送到前台 echo json_encode($result); 然后再在js页面中的 ...

  2. js中关于一个数组中最大、最小值以及它们的下标的输出的一种解决办法

    今天在学习js中的数组时,遇到的输出一个数组中最大.最小值以及它们的下表,以下是自己的解决方法! <script type="text/javascript"> var ...

  3. jquery ajax中支持哪些返回类型以及js中判断一个类型常用的方法?

    1 jquery ajax中支持哪些返回类型在JQuery中,AJAX有三种实现方式:$.ajax() , $.post , $.get(). 预期服务器返回的数据类型.如果不指定,jQuery 将自 ...

  4. Js中的一个日期处理格式化函数

    由于在工作中,经常需要对日期进行格式化,不像后端那样,有方便的方法可调用,可以在date的对象prototype中定义一个format方法,见如下 //日期时间原型增加格式化方法 Date.proto ...

  5. js中的一个方法怎么将数据主动传给另一个方法

    项目有这样的一个需求,一个不断接收实时数据的有返回值的js方法Function A在运行,同时我想将接收到的这些数据进行分解提取想要的部分并传给Function B.如何实现? Function A( ...

  6. JS中判断一个数组是否有相同数据的

    页面中有多个<select> $("select").each(function(){ str.push($(this).val());}); // join() 方法 ...

  7. JS中关于 一个关于计时器功能效果的实现

    optionSearch(); function optionSearch() { //定义一个清除计时器的变量 var timer = null; //自选标题区域 $("#optiona ...

  8. JS中以一个方法作为参数的写法

    一:以方法作为参数 这下来说直接以一个方法来作为参数的写法,直接上代码: -----------这样调用的方法------------- go(function(){ alert("succ ...

  9. js中封装一个自己的简单数学对象

    封装一个数学对象求最大值最小值 <script> var myMath={ PI:3.1415926, max:function(){ var max=arguments[0];//注意a ...

  10. js中查找一个字符是否存在。

    <script> var a = 'd'; var re = a.indexOf('d'); ){ alert('存在'); } else { alert('不存在'); } </s ...

随机推荐

  1. 前后端分离架构下使用 Sa-Token 完成登录认证

    一.架构分析 目前绝大多数系统都已经采用 "前后端分离" 架构来设计了,传统的Session模式鉴权也不再适合这种架构(或者需要额外写很多的代码来专门适配). Sa-Token 是 ...

  2. Pytorch-PyG图神经网络依赖环境安装(Anaconda)

    1.默认用户在Anaconda的虚拟环境中已安装Pytorch 2.打开anaconda prompt命令窗, activate "你的虚拟环境名称" 3.在激活后的虚拟环境下输入 ...

  3. 对象存储?CRUD Boy实现对文件的增删改查

    大家好!我是sum墨,一个一线的底层码农,平时喜欢研究和思考一些技术相关的问题并整理成文,限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教. 以下是正文! 对象存储是什么? 对象存储是一种数据 ...

  4. 十分钟了解MES系统的发展历程和标准体系

    大家好,我是Edison. 上一篇,我们通过一个点菜的故事快速地了解了MES系统都能做哪些事儿<三分钟快速了解什么是MES系统>,相信大家都有了一个基本的感性认知.本篇,我们将时间拨回几十 ...

  5. 【序列化与反序列化】关于序列化与反序列化MessagePack的实践

    在进行序列化操作之前,我们还对系统进行压测,通过jvisualvm分析cpu,线程,垃圾回收情况等:运用火焰图async-profiler分析系统性能,找出程序中占用CPU资源时间最长的代码块. 代码 ...

  6. HCL实验:4.同一vlan位于不同交换机上的通信

    拓扑图 SW1配置 SW2配置 SW3配置 VLAN 1 PC1 PING PC5 VLAN 2 PC 2 PING PC 6 VLAN 3 PC4 PING PC8 怀疑是模拟器的问题---- 不知 ...

  7. Java开发大型互联网-架构师必须掌握的分布式技术

    Java开发大型互联网-架构师必须掌握的分布式技术 摘要:在当今互联网行业,随着用户量和业务的不断增长,大型互联网系统的设计和开发已经成为了一项头等重要的任务.作为架构师,要能够应对这样的挑战,就必须 ...

  8. EC600U-4G模组,连接阿里云测试服务器和物联网平台

    原博主视频:https://www.bilibili.com/video/BV1yT4y1P7Gw?share_source=copy_web 连接阿里云服务器 !!需要公网ip(服务器)才能远程,不 ...

  9. CenOS 安装 mysql 临时密码 处理

    数据库 版本 Server version: 8.0.26 MySQL Community Server - GPL:官网下载的包 wget https://cdn.mysql.com//Downlo ...

  10. Go语言中指针详解

    指针在 Go 语言中是一个重要的特性,它允许你引用和操作变量的内存地址.下面是指针的主要作用和相关示例代码: 1. 引用传递 在 Go 中,所有的变量传递都是值传递,即复制变量的值.如果你想在一个函数 ...