「这是我参与2022首次更文挑战的第32天,活动详情查看:2022首次更文挑战」
示例代码采用three.js-r73版本: cdnjs.cloudflare.com/ajax/libs/t…
上一节,我们通过THREE.BufferGeometry高性能地创建了160万个三角形,其中我们给geometry设置了computeBoundingSphere方法,这个方法是用来实现包围盒的,具体怎么做的呢,让我们来看看源码吧。
computeBoundingSphere
- 如果我们不使用这个方法,我们显示效果上是没有什么变化的,因为它不涉及具体的显示。
- 这个方法可以用来计算碰撞检测,检测两个物体是否相撞(以后有时间具体实战下)
计算立方体包围盒:
假设我们有一个球形物体,我们需要计算包围这个球体的立方体,我们需要找到最里面和最外面的点的坐标,然后通过平移的方式,画出立方体。所以我们需要找到所有点的最大xyz坐标和最小xyz坐标,也就找到了那两个点
计算球体包围盒
上面是计算立方体包围盒的方法,那计算球体包围盒应该怎么做呢?
- 假设我们有这么一个物体(中间乱线),外面的圆时球体包围盒,想计算这个包围盒需要先找到中心点,然后找到半径,就可以计算了。
查看源码实现
- 我们找到threejs源码->src/core/BufferGeometry.js->computeBoundingSphere方法
初始化定义
- 首先是定义了一个立方体和一个向量,返回了一个函数供调用
computeBoundingSphere: function () {
var box = new THREE.Box3(); // 在3D空间中表示一个盒子或立方体
var vector = new THREE.Vector3(); // 创建一个向量
// 返回了一个函数
return function () {
....
}
}
判断是否有球形包围盒
- 然后判断是不是有球形包围盒,如果没有创建一个球体
- 把设置的坐标点进行存储
// 如果 球体边界 是空,创建一个球体,也就是包围我们物体的球体
if (this.boundingSphere === null) {
this.boundingSphere = new THREE.Sphere(); // 球体
}
var positions = this.attributes.position.array; // 获取位置数组
计算立方体包围盒
- 如果有坐标点,开始计算立方体包围盒
- 先清空包围盒,进行初始化
- 设置中心点,默认和球体中心点一样
/* -----计算立方体包围盒----- */
box.makeEmpty(); // 清空包围盒
var center = this.boundingSphere.center; // 获取中心点,默认是0
for (var i = 0, il = positions.length; i < il; i += 3) {
// 矩阵 偏移量
vector.fromArray(positions, i); // 由顶点数组创建向量
box.expandByPoint(vector); // 存储最小和最大的向量值,让盒子包含这个向量值,也就是取向量中最大和最小xyz值进行存储
}
box.center(center); // 设置中心点
vector.fromArray,这个方法可以通过传递的数组,加上偏移量,设置一个向量- 由于我们遍历的时候是i+3,所以每三个字段组成一个点,刚好赋值给vector
fromArray: function ( array, offset ) {
if ( offset === undefined ) offset = 0;
this.x = array[ offset ];
this.y = array[ offset + 1 ];
this.z = array[ offset + 2 ];
return this;
},
box.expandByPoint这个方法会将传入的向量点进行比较,保留向量最大的xyz值,和最小的xyz值,作为最大向量和最小向量- 这里调用的
min( point )``max( point )是Vector3上最大最小方法,它会返回最大最小xyz值
- 这里调用的
expandByPoint: function ( point ) {
this.min.min( point );
this.max.max( point );
return this;
},
计算球体包围盒
- 初始化最大半径
- 通过取离中心点最远的距离可以得到最大半径
- 如果没有计算出半径,程序会报错
/* ------计算球体包围盒----- */
var maxRadiusSq = 0; // 最大半径
for (var i = 0, il = positions.length; i < il; i += 3) {
vector.fromArray(positions, i);
// 取离中心点最远的距离
maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(vector));
}
this.boundingSphere.radius = Math.sqrt(maxRadiusSq); // 开根号,得到半径
// 如果没有计算出半径,就会报错
if (isNaN(this.boundingSphere.radius)) {
console.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this);
}
- 以上就是我们对于computeBoundingSphere源码的解析,通过这个方法我们就可以设置模型的立方体包围盒盒球体包围盒了。