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. selenium4-获取页面元素相关信息

    本小节我们简单说下如何使用selenium4-获取页面元素相关信息,以及获取页面元素的相关信息后可以做什么. 获取页面元素的主要目的:(1)执行完步骤后进行断言:(2)获取前一步骤的响应结果作为后续步 ...

  2. 解决google翻译出错问题

    解决google翻译问题 一.为什么失效 因为google把google翻译的API给关闭了,导致翻译不了. 据网上说是服务器耗钱,但盈利不够导致的. 二.可修复的前提 国内还存有服务器可以用API ...

  3. CentOS7 配置本地yum源软件仓库

    CentOS7 配置本地yum源软件仓库 前言 配置本地yum源软件仓库可以离线状态下安装本地已有的软件 先连接虚拟光驱,对应的光驱iso文件 查看磁盘分区状态 可以看到sr0 未挂载 [root@l ...

  4. 尚医通-day12【token续期和就诊人管理】(内附源码)

    页面预览 就诊人管理 就诊人列表 添加就诊人 查看就诊人 ![image-20230225060710 管理员系统用户管理 前面我们完成了用户登录.用户认证与就诊人管理,现在我们需要把这些信息在我们的 ...

  5. java中基本数据类型和包装数据类型

    基本数据类型和包装数据类型在 Java 中有着重要的区别和联系,对于 Java 程序员来说,熟悉这两种数据类型的特点和使用方法是非常必要的. 基本数据类型 Java 中的基本数据类型一共有 8 种,分 ...

  6. 3 大数据实战系列-spark shell分析日志

    1 准备数据源 文件格式: 访问时间\t用户ID\t[查询词]\t该URL在返回结果中的排名\t用户点击的顺序号\t用户点击URL 数据文件越大越好,至少100万行 2 启动任务 ./spark-sh ...

  7. java调用WebService(未完成)记录篇

    背景: 因工作需要和一个Sap相关系统以WebService的方式进行接口联调,之前仅听过这种技术,但并没有实操过,所以将本次开发相关的踩坑进行记录 通过一个实例来认识webservice 服务端 首 ...

  8. LeetCode 周赛上分之旅 #33 摩尔投票派上用场

    ️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 [BaguTree Pro] 知识星球提问. 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思 ...

  9. nginx配置文件内容(1)

    nginx.conf内容 在Nginx服务器的主配置文件nginx.conf中,包括全局配置.I/O事件配置.HTTP配置这三大块内容,配置语句的格式为"关键字  值:"(末尾以分 ...

  10. Python数据分析易错知识点归纳(三):Pandas

    三.pandas 不带括号的基本属性 df.index # 结果是一个Index对象, 可以使用等号重新赋值,如: df.index = ['a', 'b', 'c'] df.columns # 结果 ...