📄 aabb3.cpp
字号:
{
// 检查法向量,计算最大和最小D值,即距离
Vector3 n(plane.a, plane.b, plane.c);
float d = plane.d;
float minD, maxD;
if (n.x > 0.f)
{
minD = n.x * min.x;
maxD = n.x * max.x;
}
else
{
minD = n.x * max.x;
maxD = n.x * min.x;
}
if (n.y > 0.f)
{
minD += n.y * min.y;
maxD += n.y * max.y;
}
else
{
minD += n.y * max.y;
maxD += n.y * min.y;
}
if (n.z > 0.f)
{
minD += n.z * min.z;
maxD += n.z * max.z;
}
else
{
minD += n.z * max.z;
maxD += n.z * min.z;
}
// 完全在平面的前面
if (minD >= d)
{
return 1;
}
// 完全在平面的背面
if (maxD <= d)
{
return -1;
}
// 横跨平面
return 0;
}
//-------------------------------------------------------------------------------
// 动态检测和面的交集,返回时间参数
//-------------------------------------------------------------------------------
//-------------------------------------------------------------------------------
// 跟OBB的碰撞检测
// vRadiiB是传入盒子的尺寸(x,y,z的一半长),假定它在自己空间原点
// mToA是从传入盒子到我们AABB空间的变换矩阵
//-------------------------------------------------------------------------------
bool AABB3::IntersectOBB(const Vector3 &bRadii, const CMatrix44F &mToA) const
{
Vector3 p;
mToA.GetRow(3, &p); // 得到OBB的中心的位置
Vector3 aCenter = min + max;
aCenter *= 0.5f; // 得到本AABB的位置
p -= aCenter; // 这个得到OBB中心到本AABB中心的距离
Vector3 aRadii = max - min;
aRadii *= 0.5f; // AABB的半径
float absXX, absXY, absXZ; // X轴的向量方向
float absYX, absYY, absYZ; // Y轴的向量方向
float absZX, absZY, absZZ; // Z轴的向量方向
const float * f = mToA.m;
// 一,先在AABB盒子的每个坐标轴上投影,判断有没有相交
// ***
// * *
// * *
// ************* ** * *
// * * ** *
// * * * **
// * *
// ************* bRadii.x * absXX
// \/
// |aRadii.x| | | | <---bRadii.y * absYX
//-------------------------------------------------------
// | p.x |
// 取出每个轴向量的x分量
absXX = fabs(f[0]);
absYX = fabs(f[4]);
absZX = fabs(f[8]);
// 如果两个盒子在X轴上的总距离小于两个中心的X距离则没有相交
if (aRadii.x + bRadii.x * absXX + bRadii.y * absYX + bRadii.z * absZX - fabs(p.x)<0.0f)
return false;
// 取出每个轴的y分量
absXY = fabs(f[1]);
absYY = fabs(f[5]);
absZY = fabs(f[9]);
// 如果两个盒子在Y轴上的总距离小于两个中心的Y距离则没有相交
if (aRadii.y + bRadii.x * absXY + bRadii.y * absYY + bRadii.z * absZY - fabs(p.y)<0.0f)
return false;
// 取出每个轴的z分量
absXZ = fabs(f[2]);
absYZ = fabs(f[6]);
absZZ = fabs(f[10]);
// 如果两个盒子在Z轴上的总距离小于两个中心的Z距离则没有相交
if (aRadii.z + bRadii.x * absXZ + bRadii.y * absYZ + bRadii.z * absZZ - fabs(p.z)<0.0f)
return false;
// 二、然后在OBB的坐标轴上投影,判断有没有相交
// 如果两个盒子在OBB的X轴上的总距离小于两个中心的X距离则没有相交
if (aRadii.x*absXX + aRadii.y*absXY + aRadii.z*absXZ + bRadii.x - fabs(p.x*f[0] + p.y*f[1] + p.z*f[2])<0.0f)
return false;
// 如果两个盒子在OBB的Y轴上的总距离小于两个中心的Y距离则没有相交
if (aRadii.x*absYX + aRadii.y*absYY + aRadii.z*absYZ + bRadii.y - fabs(p.x*f[4] + p.y*f[5] + p.z*f[6])<0.0f)
return false;
// 如果两个盒子在OBB的Z轴上的总距离小于两个中心的Z距离则没有相交
if (aRadii.x*absZX + aRadii.y*absZY + aRadii.z*absZZ + bRadii.z - fabs(p.x*f[8] + p.y*f[9] + p.z*f[10])<0.0f)
return false;
// 三、在AABB与OBB的三个轴的叉乘向量上投影,判断有没有相交
// 在两个盒子的X轴叉乘的向量上投影,判断有没有相交
// 投影轴为:(1, 0, 0) X (f[0], f[1], f[2]) = (0, -f[2], f[1])
if (fabs(p.z*f[1] - p.y*f[2]) >
aRadii.y * absXZ + aRadii.z * absXY +
bRadii.y * absZX + bRadii.z * absYX)
return false;
// 投影轴为:(1, 0, 0) X (f[4], f[5], f[6]) = (0, -f[6], f[5])
if (fabs(p.z*f[5] - p.y*f[6]) >
aRadii.y * absYZ + aRadii.z * absYY +
bRadii.x * absZX + bRadii.z * absXX)
return false;
// 投影轴为:(1, 0, 0) X (f[8], f[9], f[10]) = (0, -f[10], f[9])
if (fabs(p.z*f[9] - p.y*f[10]) >
aRadii.y * absZZ + aRadii.z * absZY +
bRadii.x * absYX + bRadii.y * absXX)
return false;
// 投影轴为:(0, 1, 0) X (f[0], f[1], f[2]) = (f[2], 0, -f[0])
if (fabs(p.x*f[2] - p.z*f[0]) >
aRadii.x * absXZ + aRadii.z * absXX +
bRadii.y * absZY + bRadii.z * absYY)
return false;
// 投影轴为:(0, 1, 0) X (f[4], f[5], f[6]) = (f[6], 0, -f[4])
if (fabs(p.x*f[6] - p.z*f[4]) >
aRadii.x * absYZ + aRadii.z * absYX +
bRadii.x * absZY + bRadii.z * absXY)
return false;
// 投影轴为:(0, 1, 0) X (f[8], f[9], f[10]) = (f[10], 0, -f[8])
if (fabs(p.x*f[10] - p.z*f[8]) >
aRadii.x * absZZ + aRadii.z * absZX +
bRadii.x * absYY + bRadii.y * absXY)
return false;
// 投影轴为:(0, 0, 1) X (f[0], f[1], f[2]) = (-f[1], f[0], 0)
if (fabs(p.y*f[0] - p.x*f[1]) >
aRadii.x * absXY + aRadii.y * absXX +
bRadii.y * absZZ + bRadii.z * absYZ)
return false;
// 投影轴为:(0, 0, 1) X (f[4], f[5], f[6]) = (-f[5], f[4], 0)
if (fabs(p.y*f[4] - p.x*f[5]) >
aRadii.x * absYY + aRadii.y * absYX +
bRadii.x * absZZ + bRadii.z * absXZ)
return false;
// 投影轴为:(0, 0, 1) X (f[8], f[9], f[10]) = (-f[9], f[8], 0)
if (fabs(p.y*f[8] - p.x*f[9]) >
aRadii.x * absZY + aRadii.y * absZX +
bRadii.x * absYZ + bRadii.y * absXZ)
return false;
return true;
}
//-------------------------------------------------------------------------------
// 判断两个盒子是否重叠了,还可以通过参数返回重叠部分。
//-------------------------------------------------------------------------------
bool IntersectAABBs(const AABB3 &box1, const AABB3 &box2, AABB3 *boxIntersect)
{
// 检测没有重叠的情况
if (box1.min.x > box2.max.x) return false;
if (box1.max.x < box2.min.x) return false;
if (box1.min.y > box2.max.y) return false;
if (box1.max.y < box2.min.y) return false;
if (box1.min.z > box2.max.z) return false;
if (box1.max.z < box2.min.z) return false;
// 有重叠,如果需要返回重叠部分,则计算一下
if (boxIntersect != NULL)
{
boxIntersect->min.x = __max(box1.min.x, box2.min.x);
boxIntersect->max.x = __min(box1.max.x, box2.max.x);
boxIntersect->min.y = __max(box1.min.y, box2.min.y);
boxIntersect->max.y = __min(box1.max.y, box2.max.y);
boxIntersect->min.z = __max(box1.min.z, box2.min.z);
boxIntersect->max.z = __min(box1.max.z, box2.max.z);
}
// 返回相交了
return true;
}
//-------------------------------------------------------------------------------
// 动态检测两个盒子的碰撞,返回时间参数,无碰撞,则返回>1的数
//-------------------------------------------------------------------------------
// AABB与三角形的相交
///// 1. 判断三角形的任一顶点是否被AABB包含
///// 2. 判断三角形的任一边是否与AABB相交
///// 2.1 先判断任一边所在射线与AABB是否相交
///// 2.2 再判断相交点距离是否小于这条边的边长
///// </remarks>
///// <param name="aabb"></param>
///// <param name="A">三角形顶点一</param>
///// <param name="B">三角形顶点二</param>
///// <param name="C">三角形顶点三</param>
///// <returns>相交情况</returns>
//public static bool Intersects(AxisAlignedBox aabb, Vector3 A, Vector3 B, Vector3 C)
//{
// if (aabb.IsContainVector(A) || aabb.IsContainVector(B)|| aabb.IsContainVector(C))
// return true;
//
// Vector3[] vertexs = new Vector3[]{A,B,C};
// Vector3[] edges = new Vector3[]{B - A, C - B, A - C};
// Ray ray = null; IntersectResult result;
//
// for(int i = 0; i < 3; i++)
// {
// ray = new Ray(vertexs[i], edges[i]);
// result = Intersects(ray, aabb);
// if(result.Hit && result.Distance * result.Distance < edges[i].LengthSq())
// return true;
// }
// return false;
//}
///// <summary>
///// 是否与指定的AABB相交
///// </summary>
///// <param name="box"></param>
///// <returns></returns>
//public override Intersection Intersect(AxisAlignedBox box)
//{
// Intersection result = base.Intersect(box);
// // 如果与AABB相交,再进行三角形级别的碰撞检测
// if(result != Intersection.None)
// {
// Matrix M = this.ParentNodeFullTransform;
// Vector3 A,B,C;
// for(int i = 0; i < this.mesh.Geom.TriangleCount; i++)
// {
// A = Vector3.TransformCoordinate(this.mesh.Geom.Vertices[this.mesh.Geom.TriangleIndex[i * 3]], M);
// B = Vector3.TransformCoordinate(this.mesh.Geom.Vertices[this.mesh.Geom.TriangleIndex[i * 3 + 1]], M);
// C = Vector3.TransformCoordinate(this.mesh.Geom.Vertices[this.mesh.Geom.TriangleIndex[i * 3 + 2]], M);
// if(Smart.Maths.MathUtil.Intersects(box, A, B, C))
// return Intersection.Partial;
// }
// }
// return Intersection.None;
//}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -