修复OBB的实现

pull/445/MERGE
ChenX 5 years ago
parent bd71c9b19d
commit 56e034686a

@ -14,10 +14,11 @@ import { BSPGroupParse } from "../../Geometry/BSPGroupParse";
import { FastWireframe } from "../../Geometry/CreateWireframe"; import { FastWireframe } from "../../Geometry/CreateWireframe";
import { EdgesGeometry } from "../../Geometry/EdgeGeometry"; import { EdgesGeometry } from "../../Geometry/EdgeGeometry";
import { equaln, equalv2, equalv3, isIntersect, isParallelTo, MoveMatrix, ZeroVec } from "../../Geometry/GeUtils"; import { equaln, equalv2, equalv3, isIntersect, isParallelTo, MoveMatrix, ZeroVec } from "../../Geometry/GeUtils";
import { OBB } from "../../Geometry/OBB/obb";
import { ScaleUV } from "../../Geometry/UVUtils"; import { ScaleUV } from "../../Geometry/UVUtils";
import { RenderType } from "../../GraphicsSystem/RenderType"; import { RenderType } from "../../GraphicsSystem/RenderType";
import { BlockTableRecord } from "../BlockTableRecord"; import { BlockTableRecord } from "../BlockTableRecord";
import { Factory, CADFactory } from "../CADFactory"; import { CADFactory, Factory } from "../CADFactory";
import { CADFiler } from "../CADFiler"; import { CADFiler } from "../CADFiler";
import { Contour } from "../Contour"; import { Contour } from "../Contour";
import { Shape } from "../Shape"; import { Shape } from "../Shape";
@ -101,6 +102,11 @@ export class ExtrudeSolid extends Entity
return new Box3Ext(new Vector3(), new Vector3(this.width, this.height, this.thickness)); return new Box3Ext(new Vector3(), new Vector3(this.width, this.height, this.thickness));
} }
get OBB(): OBB
{
return new OBB(this.OCS, new Vector3(this.width, this.height, this.thickness).multiplyScalar(0.5));
}
get GroovesAddLength() get GroovesAddLength()
{ {
return this.groovesAddLength; return this.groovesAddLength;

@ -1,145 +1,212 @@
import * as THREE from 'three'; import { Vector3, Matrix4 } from 'three';
import { CoordinateSystem } from '../CoordinateSystem';
// Quote from:
// https://github.com/Mugen87/yume/blob/master/src/javascript/engine/etc/OBB.js
// 即obb.js(本项目中已存在)
// Reference material:
//https://stackoverflow.com/questions/28499800/oriented-box-intersection-in-threejs //https://stackoverflow.com/questions/28499800/oriented-box-intersection-in-threejs
//http://www.cnblogs.com/iamzhanglei/archive/2012/06/07/2539751.html //http://www.cnblogs.com/iamzhanglei/archive/2012/06/07/2539751.html
//https://github.com/Mugen87/yume/blob/master/src/javascript/engine/etc/OBB.js //https://github.com/Mugen87/yume/blob/master/src/javascript/engine/etc/OBB.js
export class OBB export class OBB
{ {
m_CoordinateSystem: CoordinateSystem; _EPSILON = 1e-3;
halfSizes: THREE.Vector3
constructor(postion?: CoordinateSystem, size?: THREE.Vector3) public center: Vector3;
constructor(public ocs: Matrix4, public halfSizes: Vector3)
{ {
this.m_CoordinateSystem = postion || new CoordinateSystem(); this.center = halfSizes.clone().applyMatrix4(ocs);
this.halfSizes = size || new THREE.Vector3();
} }
getCenter(): THREE.Vector3 intersectsOBB(obb: OBB): boolean
{ {
let v = this.m_CoordinateSystem.Postion.clone(); let xAxisA = new Vector3();
v.add(this.m_CoordinateSystem.XAxis.clone().multiplyScalar(this.halfSizes.x * 0.5)) let yAxisA = new Vector3();
v.add(this.m_CoordinateSystem.YAxis.clone().multiplyScalar(this.halfSizes.y * 0.5)) let zAxisA = new Vector3();
v.add(this.m_CoordinateSystem.ZAxis.clone().multiplyScalar(this.halfSizes.y * 0.5))
return v; let xAxisB = new Vector3();
let yAxisB = new Vector3();
let zAxisB = new Vector3();
let translation = new Vector3();
let vector = new Vector3();
let axisA: Vector3[] = [];
let axisB: Vector3[] = [];
let rotationMatrix = [[], [], []];
let rotationMatrixAbs = [[], [], []];
let halfSizeA: number, halfSizeB: number;
let t: number, i: number;
// extract each axis
this.ocs.extractBasis(xAxisA, yAxisA, zAxisA);
obb.ocs.extractBasis(xAxisB, yAxisB, zAxisB);
// push basis vectors into arrays, so you can access them via indices
axisA.push(xAxisA, yAxisA, zAxisA);
axisB.push(xAxisB, yAxisB, zAxisB);
// get displacement vector
vector.subVectors(obb.center, this.center);
// express the translation vector in the coordinate frame of the current
// OBB (this)
for (i = 0; i < 3; i++)
{
translation.setComponent(i, vector.dot(axisA[i]));
} }
intersectsOBB(obb: OBB)
// generate a rotation matrix that transforms from world space to the
// OBB's coordinate space
for (i = 0; i < 3; i++)
{ {
// assumes the position of each box to be an orthonormal basis for (let j = 0; j < 3; j++)
var pos1 = this.m_CoordinateSystem.getMatrix4() {
var pos2 = obb.m_CoordinateSystem.getMatrix4() rotationMatrix[i][j] = axisA[i].dot(axisB[j]);
var center1 = this.getCenter(); rotationMatrixAbs[i][j] = Math.abs(rotationMatrix[i][j]) + this._EPSILON;
var center2 = obb.getCenter(); }
var centerDifference = center1.clone().sub(center2) }
var results = { // test the three major axes of this OBB
intersects: true, for (i = 0; i < 3; i++)
resolution: null {
}; vector.set(rotationMatrixAbs[i][0], rotationMatrixAbs[i][1], rotationMatrixAbs[i][2]);
// broad phase halfSizeA = this.halfSizes.getComponent(i);
var maxDiameter1 = this.halfSizes.length(); halfSizeB = obb.halfSizes.dot(vector);
var maxDiameter2 = obb.halfSizes.length();
if (centerDifference.length() > maxDiameter1 + maxDiameter2) if (Math.abs(translation.getComponent(i)) > halfSizeA + halfSizeB)
{ {
results.intersects = false; return false;
return results; }
} }
// narrow phase // test the three major axes of other OBB
for (i = 0; i < 3; i++)
{
vector.set(rotationMatrixAbs[0][i], rotationMatrixAbs[1][i], rotationMatrixAbs[2][i]);
// get the axis vectors of the first box halfSizeA = this.halfSizes.dot(vector);
var ax1 = new THREE.Vector3() halfSizeB = obb.halfSizes.getComponent(i);
var ay1 = new THREE.Vector3()
var az1 = new THREE.Vector3()
this.m_CoordinateSystem.extractBasis(ax1, ay1, az1);
// get the axis vectors of the second box
var ax2 = new THREE.Vector3()
var ay2 = new THREE.Vector3()
var az2 = new THREE.Vector3()
obb.m_CoordinateSystem.extractBasis(ax2, ay2, az2);
// keep them in a list vector.set(rotationMatrix[0][i], rotationMatrix[1][i], rotationMatrix[2][i]);
var axes = [ax1, ay1, az1, ax2, ay2, az2]; t = translation.dot(vector);
// get the orientated radii vectors of the first box if (Math.abs(t) > halfSizeA + halfSizeB)
var radX1 = ax1.clone().multiplyScalar(this.halfSizes.x) {
var radY1 = ay1.clone().multiplyScalar(this.halfSizes.y) return false;
var radZ1 = az1.clone().multiplyScalar(this.halfSizes.z) }
}
// get the orientated radii vectors of the second box // test the 9 different cross-axes
var radX2 = ax2.clone().multiplyScalar(obb.halfSizes.x)
var radY2 = ay2.clone().multiplyScalar(obb.halfSizes.y)
var radZ2 = az2.clone().multiplyScalar(obb.halfSizes.z)
var smallestDifference = Infinity; // A.x <cross> B.x
// there are 15 axes to check, so loop through all of them until a separation plane is found halfSizeA = this.halfSizes.y * rotationMatrixAbs[2][0] + this.halfSizes.z * rotationMatrixAbs[1][0];
var zeros = new THREE.Vector3() halfSizeB = obb.halfSizes.y * rotationMatrixAbs[0][2] + obb.halfSizes.z * rotationMatrixAbs[0][1];
for (var i = 0; i < 15; i++)
{ t = translation.z * rotationMatrix[1][0] - translation.y * rotationMatrix[2][0];
var axis: THREE.Vector3;
// the first 6 axes are just the axes of each bounding box if (Math.abs(t) > halfSizeA + halfSizeB)
if (i < 6)
{ {
axis = axes[i]; return false;
} }
// the last 9 axes are the cross product of all combinations of the first 6 axes
else // A.x < cross> B.y
halfSizeA = this.halfSizes.y * rotationMatrixAbs[2][1] + this.halfSizes.z * rotationMatrixAbs[1][1];
halfSizeB = obb.halfSizes.x * rotationMatrixAbs[0][2] + obb.halfSizes.z * rotationMatrixAbs[0][0];
t = translation.z * rotationMatrix[1][1] - translation.y * rotationMatrix[2][1];
if (Math.abs(t) > halfSizeA + halfSizeB)
{ {
var offset = i - 6; return false;
var j = Math.floor(offset / 3); }
var k = offset % 3;
axis = axes[j].clone().cross(axes[k + 3]) // A.x <cross> B.z
if (axis.equals(zeros)) halfSizeA = this.halfSizes.y * rotationMatrixAbs[2][2] + this.halfSizes.z * rotationMatrixAbs[1][2];
halfSizeB = obb.halfSizes.x * rotationMatrixAbs[0][1] + obb.halfSizes.y * rotationMatrixAbs[0][0];
t = translation.z * rotationMatrix[1][2] - translation.y * rotationMatrix[2][2];
if (Math.abs(t) > halfSizeA + halfSizeB)
{ {
// axes must be collinear, ignore return false;
continue;
} }
// A.y <cross> B.x
halfSizeA = this.halfSizes.x * rotationMatrixAbs[2][0] + this.halfSizes.z * rotationMatrixAbs[0][0];
halfSizeB = obb.halfSizes.y * rotationMatrixAbs[1][2] + obb.halfSizes.z * rotationMatrixAbs[1][1];
t = translation.x * rotationMatrix[2][0] - translation.z * rotationMatrix[0][0];
if (Math.abs(t) > halfSizeA + halfSizeB)
{
return false;
} }
// A.y <cross> B.y
halfSizeA = this.halfSizes.x * rotationMatrixAbs[2][1] + this.halfSizes.z * rotationMatrixAbs[0][1];
halfSizeB = obb.halfSizes.x * rotationMatrixAbs[1][2] + obb.halfSizes.z * rotationMatrixAbs[1][0];
// get the projections of the first half box onto the axis t = translation.x * rotationMatrix[2][1] - translation.z * rotationMatrix[0][1];
var projAx1 = Math.abs(radX1.dot(axis));
var projAy1 = Math.abs(radY1.dot(axis));
var projAz1 = Math.abs(radZ1.dot(axis));
// get the projections of the second half box onto the axis if (Math.abs(t) > halfSizeA + halfSizeB)
var projAx2 = Math.abs(radX2.dot(axis)); {
var projAy2 = Math.abs(radY2.dot(axis)); return false;
var projAz2 = Math.abs(radZ2.dot(axis)); }
// sum the projections // A.y <cross> B.z
var projectionBoxesSum = projAx1 + projAy1 + projAz1 + projAx2 + projAy2 + projAz2; halfSizeA = this.halfSizes.x * rotationMatrixAbs[2][2] + this.halfSizes.z * rotationMatrixAbs[0][2];
halfSizeB = obb.halfSizes.x * rotationMatrixAbs[1][1] + obb.halfSizes.y * rotationMatrixAbs[1][0];
// get the projection of the center difference onto the axis t = translation.x * rotationMatrix[2][2] - translation.z * rotationMatrix[0][2];
var projectionDifference = Math.abs(centerDifference.dot(axis));
if (projectionDifference >= projectionBoxesSum * 0.5) if (Math.abs(t) > halfSizeA + halfSizeB)
{ {
// If the projection of the center difference onto the axis is greater return false;
// than the sum of the box projections, then we found a separating plane!
// The bounding boxes therefore must not intersect
results.intersects = false;
break;
} }
else
// A.z <cross> B.x
halfSizeA = this.halfSizes.x * rotationMatrixAbs[1][0] + this.halfSizes.y * rotationMatrixAbs[0][0];
halfSizeB = obb.halfSizes.y * rotationMatrixAbs[2][2] + obb.halfSizes.z * rotationMatrixAbs[2][1];
t = translation.y * rotationMatrix[0][0] - translation.x * rotationMatrix[1][0];
if (Math.abs(t) > halfSizeA + halfSizeB)
{ {
// keep track of the difference, the smallest gives the minimum distance return false;
// and direction to move the boxes such that they no longer intersect }
var difference = projectionBoxesSum - projectionDifference;
if (difference < smallestDifference) // A.z <cross> B.y
halfSizeA = this.halfSizes.x * rotationMatrixAbs[1][1] + this.halfSizes.y * rotationMatrixAbs[0][1];
halfSizeB = obb.halfSizes.x * rotationMatrixAbs[2][2] + obb.halfSizes.z * rotationMatrixAbs[2][0];
t = translation.y * rotationMatrix[0][1] - translation.x * rotationMatrix[1][1];
if (Math.abs(t) > halfSizeA + halfSizeB)
{ {
results.resolution = axis.clone().multiplyScalar(difference); return false;
smallestDifference = difference;
} }
// A.z <cross> B.z
halfSizeA = this.halfSizes.x * rotationMatrixAbs[1][2] + this.halfSizes.y * rotationMatrixAbs[0][2];
halfSizeB = obb.halfSizes.x * rotationMatrixAbs[2][1] + obb.halfSizes.y * rotationMatrixAbs[2][0];
t = translation.y * rotationMatrix[0][2] - translation.x * rotationMatrix[1][2];
if (Math.abs(t) > halfSizeA + halfSizeB)
{
return false;
} }
// no separating axis exists, so the two OBB don't intersect
return true;
} }
// could not find a separating plane, they must intersect
return results;
};
// setFromObject(obj: THREE.Mesh): OBB; // setFromObject(obj: THREE.Mesh): OBB;
// setFromAABB(aabb: THREE.Box3): OBB; // setFromAABB(aabb: THREE.Box3): OBB;
@ -165,5 +232,3 @@ export class OBB
// clone(obb: OBB): OBB // clone(obb: OBB): OBB
} }

Loading…
Cancel
Save