OBB(Oriented Bounding Box)有向包围盒。具体概念和算法网上很多,这里就不赘述了,直接上代码。
先看测试演示Demo: OBB相交检测测试演示,方便实际尝试,界面效果如下图:
上图所用的主要源码在下面给出(代码中用到的Vecter3相关的源码很常见,这里就不给出了)。
C++源码:
template
NumberType OBB
template
NumberType OBB
template
OBB
:
version(-1),
radius(0.0f),
m_ts{0.0f},
extents{0.0}
{
}
template
void OBB
{
version++;
for (auto i = 0; i < 3; ++i) axes[i].normalize();
auto et = extent;
radius = et.getLength();
//et.toArray3(extents.data());
et.toArray3(extents);
}
template
bool OBB
{
m_pv.subVecsTo(pv, center);
auto v0 = m_pv;
using namespace std;
auto& et = extent;
return abs(v0.dot(axes[0])) <= et.x && abs(v0.dot(axes[1])) <= et.y && abs(v0.dot(axes[2])) <= et.z;
}
template
bool OBB
{
auto& a = *this;
auto& b = obb;
using namespace std;
// 计算距离向量tv
m_pv.subVecsTo(b.center, a.center);
auto& tv = m_pv;
if (tv.getLength() - (a.radius + b.radius) > epsilon)
{
return false;
}
auto Avs = OBB
auto Rvs = OBB
// 计算旋转矩阵R
for (auto i = 0; i < 3; ++i)
{
for (auto j = 0; j < 3; ++j)
{
Rvs[i][j] = a.axes[i].dot(b.axes[j]);
}
}
// 应用距离向量tv
auto ts = m_ts;
ts[0] = tv.dot(a.axes[0]);
ts[1] = tv.dot(a.axes[1]);
ts[2] = tv.dot(a.axes[2]);
// 计算旋转矩阵R的绝对值AbsR
for (auto i = 0; i < 3; ++i)
{
for (auto j = 0; j < 3; ++j)
{
Avs[i][j] = abs(Rvs[i][j]) + epsilon;
}
}
auto& aets = a.extents;
auto& bets = b.extents;
NumberType ra = 0.0f;
NumberType rb = 0.0f;
// test axes(A0, A1, A2)
for (auto i = 0; i < 3; ++i)
{
ra = aets[i];
rb = bets[0] * Avs[i][0] + bets[1] * Avs[i][1] + bets[2] * Avs[i][2];
if (abs(ts[i]) > ra + rb) return false;
}
// test axes(B0, B1, B2)
for (auto i = 0; i < 3; ++i)
{
ra = aets[0] * Avs[0][i] + aets[1] * Avs[1][i] + aets[2] * Avs[2][i];
rb = bets[i];
if (abs(ts[0] * Rvs[0][i] + ts[1] * Rvs[1][i] + ts[2] * Rvs[2][i]) > ra + rb) return false;
}
// test axes L = A0 x B0
ra = aets[1] * Avs[2][0] + aets[2] * Avs[1][0];
rb = bets[1] * Avs[0][2] + bets[2] * Avs[0][1];
if (abs(ts[2] * Rvs[1][0] - ts[1] * Rvs[2][0]) > ra + rb) return false;
// test axes L = A0 x B1
ra = aets[1] * Avs[2][1] + aets[2] * Avs[1][1];
rb = bets[0] * Avs[0][2] + bets[2] * Avs[0][0];
if (abs(ts[2] * Rvs[1][1] - ts[1] * Rvs[2][1]) > ra + rb) return false;
// test axes L = A0 x B2
ra = aets[1] * Avs[2][2] + aets[2] * Avs[1][2];
rb = bets[0] * Avs[0][1] + bets[1] * Avs[0][0];
if (abs(ts[2] * Rvs[1][2] - ts[1] * Rvs[2][2]) > ra + rb) return false;
// --------------------------------------------------------------------------
// test axes L = A1 x B0
ra = aets[0] * Avs[2][0] + aets[2] * Avs[0][0];
rb = bets[1] * Avs[1][2] + bets[2] * Avs[1][1];
if (abs(ts[0] * Rvs[2][0] - ts[2] * Rvs[0][0]) > ra + rb) return false;
// test axes L = A1 x B1
ra = aets[0] * Avs[2][1] + aets[2] * Avs[0][1];
rb = bets[0] * Avs[1][2] + bets[2] * Avs[1][0];
if (abs(ts[0] * Rvs[2][1] - ts[2] * Rvs[0][1]) > ra + rb) return false;
// test axes L = A1 x B2
ra = aets[0] * Avs[2][2] + aets[2] * Avs[0][2];
rb = bets[0] * Avs[1][1] + bets[1] * Avs[1][0];
if (abs(ts[0] * Rvs[2][2] - ts[2] * Rvs[0][2]) > ra + rb) return false;
// --------------------------------------------------------------------------
// test axes L = A2 x B0
ra = aets[0] * Avs[1][0] + aets[1] * Avs[0][0];
rb = bets[1] * Avs[2][2] + bets[2] * Avs[2][1];
if (abs(ts[1] * Rvs[0][0] - ts[0] * Rvs[1][0]) > ra + rb) return false;
// test axes L = A2 x B1
ra = aets[0] * Avs[1][1] + aets[1] * Avs[0][1];
rb = bets[0] * Avs[2][2] + bets[2] * Avs[2][0];
if (abs(ts[1] * Rvs[0][1] - ts[0] * Rvs[1][1]) > ra + rb) return false;
// test axes L = A2 x B2
ra = aets[0] * Avs[1][2] + aets[1] * Avs[0][2];
rb = bets[0] * Avs[2][1] + bets[1] * Avs[2][0];
if (abs(ts[1] * Rvs[0][2] - ts[0] * Rvs[1][2]) > ra + rb) return false;
return true;
}
TypeScript源码:
import Vector3D from "../../vox/math/Vector3D";
let OR = [new Float32Array(3), new Float32Array(3), new Float32Array(3)];
let OAbsR = [new Float32Array(3), new Float32Array(3), new Float32Array(3)];
export class OBB {
private m_pv = new Vector3D();
private m_ts = [0, 0, 0];
/**
* three axes normalization 3d vectors
*/
readonly axes = [new Vector3D(), new Vector3D(), new Vector3D()];
readonly extents = new Float32Array(3);
/**
* half length of these three axes
*/
readonly extent = new Vector3D();
readonly center = new Vector3D();
version = -1;
radius = 50;
constructor() {}
reset(): void {}
update(): void {
this.version++;
for (let i = 0; i < 3; ++i) this.axes[i].normalize();
let et = this.extent;
this.radius = et.getLength();
this.extents.set([et.x, et.y, et.z]);
}
containsV(pv: Vector3D): boolean {
const v0 = this.m_pv.subVecsTo(pv, this.center);
const axes = this.axes;
const abs = Math.abs;
const et = this.extent;
return abs(v0.dot(axes[0])) <= et.x && abs(v0.dot(axes[1])) <= et.y && abs(v0.dot(axes[2])) <= et.z;
}
intersect(a: OBB, b: OBB = null, epsilon = 1e-6): boolean {
if (!b) {
b = a;
a = this;
}
const abs = Math.abs;
// 计算距离向量tv
const tv = this.m_pv.subVecsTo(b.center, a.center);
if (tv.getLength() - (a.radius + b.radius) > epsilon) {
return false;
}
let Avs = OAbsR;
let Rvs = OR;
// 计算旋转矩阵R
for (let i = 0; i < 3; ++i) {
for (let j = 0; j < 3; ++j) {
Rvs[i][j] = a.axes[i].dot(b.axes[j]);
}
}
// 应用距离向量tv
const ts = this.m_ts;
ts[0] = tv.dot(a.axes[0]);
ts[1] = tv.dot(a.axes[1]);
ts[2] = tv.dot(a.axes[2]);
// 计算旋转矩阵R的绝对值AbsR
for (let i = 0; i < 3; ++i) {
for (let j = 0; j < 3; ++j) {
Avs[i][j] = abs(Rvs[i][j]) + epsilon;
}
}
const aets = a.extents;
const bets = b.extents;
let ra = 0;
let rb = 0;
// test axes(A0, A1, A2)
for (let i = 0; i < 3; ++i) {
ra = aets[i];
rb = bets[0] * Avs[i][0] + bets[1] * Avs[i][1] + bets[2] * Avs[i][2];
if (abs(ts[i]) > ra + rb) return false;
}
// test axes(B0, B1, B2)
for (let i = 0; i < 3; ++i) {
ra = aets[0] * Avs[0][i] + aets[1] * Avs[1][i] + aets[2] * Avs[2][i];
rb = bets[i];
if (abs(ts[0] * Rvs[0][i] + ts[1] * Rvs[1][i] + ts[2] * Rvs[2][i]) > ra + rb) return false;
}
// test axes L = A0 x B0
ra = aets[1] * Avs[2][0] + aets[2] * Avs[1][0];
rb = bets[1] * Avs[0][2] + bets[2] * Avs[0][1];
if (abs(ts[2] * Rvs[1][0] - ts[1] * Rvs[2][0]) > ra + rb) return false;
// test axes L = A0 x B1
ra = aets[1] * Avs[2][1] + aets[2] * Avs[1][1];
rb = bets[0] * Avs[0][2] + bets[2] * Avs[0][0];
if (abs(ts[2] * Rvs[1][1] - ts[1] * Rvs[2][1]) > ra + rb) return false;
// test axes L = A0 x B2
ra = aets[1] * Avs[2][2] + aets[2] * Avs[1][2];
rb = bets[0] * Avs[0][1] + bets[1] * Avs[0][0];
if (abs(ts[2] * Rvs[1][2] - ts[1] * Rvs[2][2]) > ra + rb) return false;
// --------------------------------------------------------------------------
// test axes L = A1 x B0
ra = aets[0] * Avs[2][0] + aets[2] * Avs[0][0];
rb = bets[1] * Avs[1][2] + bets[2] * Avs[1][1];
if (abs(ts[0] * Rvs[2][0] - ts[2] * Rvs[0][0]) > ra + rb) return false;
// test axes L = A1 x B1
ra = aets[0] * Avs[2][1] + aets[2] * Avs[0][1];
rb = bets[0] * Avs[1][2] + bets[2] * Avs[1][0];
if (abs(ts[0] * Rvs[2][1] - ts[2] * Rvs[0][1]) > ra + rb) return false;
// test axes L = A1 x B2
ra = aets[0] * Avs[2][2] + aets[2] * Avs[0][2];
rb = bets[0] * Avs[1][1] + bets[1] * Avs[1][0];
if (abs(ts[0] * Rvs[2][2] - ts[2] * Rvs[0][2]) > ra + rb) return false;
// --------------------------------------------------------------------------
// test axes L = A2 x B0
ra = aets[0] * Avs[1][0] + aets[1] * Avs[0][0];
rb = bets[1] * Avs[2][2] + bets[2] * Avs[2][1];
if (abs(ts[1] * Rvs[0][0] - ts[0] * Rvs[1][0]) > ra + rb) return false;
// test axes L = A2 x B1
ra = aets[0] * Avs[1][1] + aets[1] * Avs[0][1];
rb = bets[0] * Avs[2][2] + bets[2] * Avs[2][0];
if (abs(ts[1] * Rvs[0][1] - ts[0] * Rvs[1][1]) > ra + rb) return false;
// test axes L = A2 x B2
ra = aets[0] * Avs[1][2] + aets[1] * Avs[0][2];
rb = bets[0] * Avs[2][1] + bets[1] * Avs[2][0];
if (abs(ts[1] * Rvs[0][2] - ts[0] * Rvs[1][2]) > ra + rb) return false;
return true;
}
}
推荐链接
发表评论