Three.js中实现一个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的实现 - 掘金 (juejin.cn)
[6] 113 Three.js的obb (OrientedboundingBox)方向包围盒的使用_暮志未晚Webgl的博客-CSDN博客
Three.js中实现一个OBBHelper的更多相关文章
- php中向前台js中传送一个二维数组
在php中向前台js中传送一个二维数组,并在前台js接收获取其中值的全过程方法: (1),方法说明:现在后台将数组发送到前台 echo json_encode($result); 然后再在js页面中的 ...
- js中关于一个数组中最大、最小值以及它们的下标的输出的一种解决办法
今天在学习js中的数组时,遇到的输出一个数组中最大.最小值以及它们的下表,以下是自己的解决方法! <script type="text/javascript"> var ...
- jquery ajax中支持哪些返回类型以及js中判断一个类型常用的方法?
1 jquery ajax中支持哪些返回类型在JQuery中,AJAX有三种实现方式:$.ajax() , $.post , $.get(). 预期服务器返回的数据类型.如果不指定,jQuery 将自 ...
- Js中的一个日期处理格式化函数
由于在工作中,经常需要对日期进行格式化,不像后端那样,有方便的方法可调用,可以在date的对象prototype中定义一个format方法,见如下 //日期时间原型增加格式化方法 Date.proto ...
- js中的一个方法怎么将数据主动传给另一个方法
项目有这样的一个需求,一个不断接收实时数据的有返回值的js方法Function A在运行,同时我想将接收到的这些数据进行分解提取想要的部分并传给Function B.如何实现? Function A( ...
- JS中判断一个数组是否有相同数据的
页面中有多个<select> $("select").each(function(){ str.push($(this).val());}); // join() 方法 ...
- JS中关于 一个关于计时器功能效果的实现
optionSearch(); function optionSearch() { //定义一个清除计时器的变量 var timer = null; //自选标题区域 $("#optiona ...
- JS中以一个方法作为参数的写法
一:以方法作为参数 这下来说直接以一个方法来作为参数的写法,直接上代码: -----------这样调用的方法------------- go(function(){ alert("succ ...
- js中封装一个自己的简单数学对象
封装一个数学对象求最大值最小值 <script> var myMath={ PI:3.1415926, max:function(){ var max=arguments[0];//注意a ...
- js中查找一个字符是否存在。
<script> var a = 'd'; var re = a.indexOf('d'); ){ alert('存在'); } else { alert('不存在'); } </s ...
随机推荐
- STL-queue(ACM)
重构函数(默认) queue<int> q; 基本操作 q.front(); // 队列最前面的元素q.back(); // 队列最后面的元素q.size(); // 返回队列长度q.em ...
- 如何让一句话木马绕过waf ?
一.什么是一句话木马? 一句话木马就是只需要一行代码的木马,短短一行代码,就能做到和大马相当的功能.为了绕过waf的检测,一句话木马出现了无数中变形,但本质是不变的:木马的函数执行了我们发送的命令. ...
- String解析及其方法
String解析及其方法 1.前言 2.什么是字符串(String) 3.字符串(String)的两种创建方式及其区别 4.字符串(String)的方法及其部分原码解析 5.字符串(String)的弊 ...
- DevOps|从腾讯TEG CDC解散聊技术中台价值和建设
近日一则腾讯TEG CDC整个部门解散的消息在很多群里炸了锅,有的唱衰互联网行业,有的唉声叹气,还有的甩锅到 AGI 的发展.总体上来说,这个事情的确已经发生了,我想从组织架构和整体效能这两方面来分析 ...
- SpringBoot 多环境切换
日常开发中一般都会有三个不同的环境,分别是开发环境(dev),测试环境(test)和生产环境(prod),不同的环境各种配置都不相同,比如数据库配置,服务器端口等等. Spring Boot 多环境配 ...
- 基于JavaFX的扫雷游戏实现(二)——游戏界面
废话环节:看过上期文章的小伙伴现在可能还是一头雾水,怎么就完成了核心内容,界面呢?哎我说别急让我先急,博主这不夜以继日地肝出了界面部分嘛.还是老规矩,不会把所有地方都照顾到,只挑一些有代表性的内容 ...
- Redis数据类型之Stream系列一
一:Stream简介 Redis Stream是5.0版本之后新增的一种数据结构,其结构类似于'仅追加日志'.但也实现了多种操作来克服'仅追加日志'的一些限制,如读取策略(xread,xrange ...
- [数据分析与可视化] 基于plottable库绘制精美表格
plottable是一个Python库,用于在matplotlib中绘制精美定制的图形表格.plottable的官方仓库地址为:plottable.本文主要参考其官方文档,plottable的官方文档 ...
- 一张图告诉你如何提高 API 性能
API 性能是指一个 API 在执行其功能时的效率和性能表现,通常用于衡量 API 的响应时间.吞吐量.可伸缩性和稳定性等方面的表现. API 性能的指标包括: 响应时间: API 的响应时间是指从发 ...
- 从零玩转系列之SpringBoot3-核心原理
一.简介 1.前置知识 ● Java17 ● Spring.SpringMVC.MyBatis ● Maven.IDEA 2.环境要求 环境&工具 版本(or later) SpringBoo ...