我可以实现AABB方法来检测碰撞,这很容易而且便宜,但我想实现OBB以获得更高的准确性,所以我创建了带有模型初始化的边界框,它由8个边界顶点和中心组成,每个帧我用转换矩阵转换所有顶点以适应定向边界框,但我无法理解检测两个OBB之间碰撞的方法,我无法理解找到一个简化而清晰的教程,用代码视角而不是数学来解释算法,因为我不是数学家。
如果我有
struct Box {
glm::vec3 vertices[8];
Box() {
for (int i = 0; i < 8; i++) {
vertices[i] = glm::vec3(0);
}
}
glm::vec3 max;
glm::vec3 min;
glm::vec3 origin;
void reCompute() {
max = vertices[0];
min = vertices[0];
for (int i = 1; i < 8; i++) {
max.x = max.x > vertices[i].x ? max.x : vertices[i].x;
max.y = max.y > vertices[i].y ? max.y : vertices[i].y;
max.z = max.z > vertices[i].z ? max.z : vertices[i].z;
min.x = min.x < vertices[i].x ? min.x : vertices[i].x;
min.y = min.y < vertices[i].y ? min.y : vertices[i].y;
min.z = min.z < vertices[i].z ? min.z : vertices[i].z;
}
origin = glm::vec3((max.x + min.x) / 2.0f, (max.y + min.y) / 2.0f, (max.z + min.z) / 2.0f);
}
//AABB intersection
bool intersects(const Box &b) const {
return (min.x < b.max.x) && (max.x > b.min.x) && (min.y < b.max.y) && (max.y > b.min.y) && (min.z < b.max.z) && (max.z > b.min.z) && *this != b;
}
bool operator==(const Box& b) const {
return (max.x == b.max.x && max.y == b.max.y && max.z == b.max.z && min.x == b.min.x && min.y == b.min.y && min.z == b.min.z);
}
bool operator!=(const Box& b) const {
return (max.x != b.max.x) || (max.y != b.max.y) || (max.z != b.max.z) || (min.x != b.min.x) || (min.y != b.min.y) || (min.z != b.min.z);
}
};
在模型初始化时,我创建了框
box.vertices[0] = glm::vec3(meshMinX, meshMinY, meshMinZ);
box.vertices[1] = glm::vec3(meshMaxX, meshMinY, meshMinZ);
box.vertices[2] = glm::vec3(meshMinX, meshMaxY, meshMinZ);
box.vertices[3] = glm::vec3(meshMaxX, meshMaxY, meshMinZ);
box.vertices[4] = glm::vec3(meshMinX, meshMinY, meshMaxZ);
box.vertices[5] = glm::vec3(meshMaxX, meshMinY, meshMaxZ);
box.vertices[6] = glm::vec3(meshMinX, meshMaxY, meshMaxZ);
box.vertices[7] = glm::vec3(meshMaxX, meshMaxY, meshMaxZ);
对于每一帧,我用模型的变换矩阵重新计算盒子
for (int n = 0; n < 8; n++) {
boxs[j].vertices[n] = glm::vec3(matrix * glm::vec4(box.vertices[n], 1));
}
boxs[j].reCompute();
要知道两个OBB是否碰撞,你可以使用SAT(分离轴定理):你必须将两个形状的所有点投影到两个形状的每一条法线上。然后你会看到,如果两个形状的投影在每条法线上重叠,就会发生碰撞。如果至少有一条法线没有重叠,那么它们就不会碰撞。仅此而已,要做到这一点,你需要一个方法,将一个向量正交投影到另一个向量上,返回一个标量,还有一个方法,查看两个区间是否重叠。
我有一些Java代码:
U在V上的正交投影:
/**
* Vec u is projected on Vec v
* @param u 2d point
* @param v 2d axe
* @return the orthogonal projection
*/
public static float orthagonalProjectionOf(Vector2f u, Vector2f v){
float norme_u = u.lenght();
float norme_v = v.lenght();
float dot_u_v = dot(u, v);
float buffer = (dot_u_v/(norme_u*norme_v))*norme_u;
if(Float.isNaN(buffer))return 0;//If the vector u is null, then is orthogonal projection is 0, not a NaN
else return buffer;
}
两个间隔的重叠:
/**
* Get the overlapping of two interval on an axis.
* @param minA
* @param maxA
* @param minB
* @param maxB
* @return true overlapping. false if there is no overlapping
*/
public static boolean isOverlapping(float minA, float maxA, float minB, float maxB) {
float minOverlap = Float.NaN;
float maxOverlap = Float.NaN;
//If B contain in A
if(minA <= minB && minB <= maxA) {
if(Float.isNaN(minOverlap) || minB < minOverlap)minOverlap = minB;
}
if(minA <= maxB && maxB <= maxA) {
if(Float.isNaN(maxOverlap) || maxB > minOverlap)maxOverlap = maxB;
}
//If A contain in B
if(minB <= minA && minA <= maxB) {
if(Float.isNaN(minOverlap) || minA < minOverlap)minOverlap = minA;
}
if(minB <= maxA && maxA <= maxB) {
if(Float.isNaN(maxOverlap) || maxA > minOverlap)maxOverlap = maxA;
}
if(Float.isNaN(minOverlap) || Float.isNaN(maxOverlap))return false; //Pas d'intersection
else return true;//Intersection
}
有了这个,你就可以做一个方法来测试两个OBB之间的碰撞:
public boolean OBBwOBB(RigidBody bodyA, RigidBody bodyB) {
Shape shapeA = bodyA.getObb().getShape();
Shape shapeB = bodyB.getObb().getShape();
short overlapCompt = 0;
//We test for each normal the projection of the two shape
//Shape A :
for(int i = 0; i < shapeA.getNbrOfNormals(); i++) {
Vector2f normal = shapeA.getNormal(i, bodyA.getAngle());
boolean overlap = overlapOnThisNormal(bodyA, bodyB, normal);
if(overlap) {
overlapCompt++;
}
}
//Shape B :
for(int i = 0; i < shapeB.getNbrOfNormals(); i++) {
Vector2f normal = shapeB.getNormal(i, bodyB.getAngle());
boolean overlap = overlapOnThisNormal(bodyA, bodyB, normal);
if(overlap){
overlapCompt++;
}
}
//Now we see if there is a collision
short howManyNormals = (short) (shapeA.getNbrOfNormals() + shapeB.getNbrOfNormals());
if(overlapCompt == howManyNormals){//If the number of overlap equal the number of normal in both shape :
return true;
}
else return false;
}
您将需要它来获得投影在向量上的两个形状的最小和最大投影:
/**
* Test if the orthogonal projection of two shape on a vector overlap.
* @param bodyA
* @param bodyB
* @param normal
* @return null if no overlap, else Vector2f(minOverlaping, maxOverlaping).
*/
public static boolean overlapOnThisNormal(RigidBody bodyA, RigidBody bodyB, Vector2f normal) {
Shape shapeA = bodyA.getObb().getShape();
Shape shapeB = bodyB.getObb().getShape();
//We test each vertex of A
float minA = Float.NaN;
float maxA = Float.NaN;
for(short j = 0; j < shapeA.getNbrOfPoint(); j++){
Vector2f vertex = shapeA.getVertex(j, bodyA.getScale().x, bodyA.getScale().y, bodyA.getPosition().x, bodyA.getPosition().y, bodyA.getAngle());
float bufferA = Vector2f.orthagonalProjectionOf(vertex, normal);
if(Float.isNaN(minA) || bufferA < minA)minA = bufferA;//Set min interval
if(Float.isNaN(maxA) || bufferA > maxA)maxA = bufferA;//Set max interval
}
//We test each vertex of B
float minB = Float.NaN;
float maxB = Float.NaN;
for(short j = 0; j < shapeB.getNbrOfPoint(); j++){
Vector2f vertex = shapeB.getVertex(j, bodyB.getScale().x, bodyB.getScale().y, bodyB.getPosition().x, bodyB.getPosition().y, bodyB.getAngle());
float bufferB = Vector2f.orthagonalProjectionOf(vertex, normal);
if(Float.isNaN(minB) || bufferB < minB)minB = bufferB;//Set min interval
if(Float.isNaN(maxB) || bufferB > maxB)maxB = bufferB;//Set max interval
}
//We test if there overlap
boolean overlap = isOverlapping(minA, maxA, minB, maxB);
return overlap;
}
我希望这对您有所帮助;)
分离轴定理的C代码实现,用于两个3D OBB之间的简单碰撞检测,如下所示:
#include <iostream>
// define the operations to be used in our 3D vertices
struct vec3
{
float x, y, z;
vec3 operator- (const vec3 & rhs) const { return{ x - rhs.x, y - rhs.y, z - rhs.z }; }
float operator* (const vec3 & rhs) const { return{ x * rhs.x + y * rhs.y + z * rhs.z }; } // DOT PRODUCT
vec3 operator^ (const vec3 & rhs) const { return{ y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x }; } // CROSS PRODUCT
vec3 operator* (const float& rhs)const { return vec3{ x * rhs, y * rhs, z * rhs }; }
};
// set the relevant elements of our oriented bounding box
struct OBB
{
vec3 Pos, AxisX, AxisY, AxisZ, Half_size;
};
// check if there's a separating plane in between the selected axes
bool getSeparatingPlane(const vec3& RPos, const vec3& Plane, const OBB& box1, const OBB&box2)
{
return (fabs(RPos*Plane) >
(fabs((box1.AxisX*box1.Half_size.x)*Plane) +
fabs((box1.AxisY*box1.Half_size.y)*Plane) +
fabs((box1.AxisZ*box1.Half_size.z)*Plane) +
fabs((box2.AxisX*box2.Half_size.x)*Plane) +
fabs((box2.AxisY*box2.Half_size.y)*Plane) +
fabs((box2.AxisZ*box2.Half_size.z)*Plane)));
}
// test for separating planes in all 15 axes
bool getCollision(const OBB& box1, const OBB&box2)
{
static vec3 RPos;
RPos = box2.Pos - box1.Pos;
return !(getSeparatingPlane(RPos, box1.AxisX, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisY, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisZ, box1, box2) ||
getSeparatingPlane(RPos, box2.AxisX, box1, box2) ||
getSeparatingPlane(RPos, box2.AxisY, box1, box2) ||
getSeparatingPlane(RPos, box2.AxisZ, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisX^box2.AxisX, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisX^box2.AxisY, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisX^box2.AxisZ, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisY^box2.AxisX, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisY^box2.AxisY, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisY^box2.AxisZ, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisZ^box2.AxisX, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisZ^box2.AxisY, box1, box2) ||
getSeparatingPlane(RPos, box1.AxisZ^box2.AxisZ, box1, box2));
}
// a quick test to see the code working
int _tmain(int argc, _TCHAR* argv[])
{
// create two obbs
OBB A, B;
// set the first obb's properties
A.Pos = { 0.f, 0.f, 0.f }; // set its center position
// set the half size
A.Half_size.x = 10.f;
A.Half_size.y = 1.f;
A.Half_size.z = 1.f;
// set the axes orientation
A.AxisX = { 1.f, 0.f, 0.f };
A.AxisY = { 0.f, 1.f, 0.f };
A.AxisZ = { 0.f, 0.f, 1.f };
// set the second obb's properties
B.Pos = { 20.f, 0.f, 0.f }; // set its center position
// set the half size
B.Half_size.x = 10.f;
B.Half_size.y = 1.f;
B.Half_size.z = 1.f;
// set the axes orientation
B.AxisX = { 1.f, 0.f, 0.f };
B.AxisY = { 0.f, 1.f, 0.f };
B.AxisZ = { 0.f, 0.f, 1.f };
// run the code and get the result as a message
if (getCollision(A, B)) std::cout << "Collision!!!" << std::endl;
else std::cout << "No collision." << std::endl;
// pause and quit
std::cout << std::endl;
system("pause");
return 0;
}
我是pygame的新手,我做了一个屏幕边框检测,但它不起作用 并检查它是否接触到边缘 但如果我们使用它就会坏掉/播放器就会卡住 整个代码是
我只使用Box2D进行碰撞检测。我的代码与Ray Wenderlich教程中的代码类似。 我遇到了这个方法的问题。由于代码绕过了Box2D模拟,因此没有碰撞响应。因此,精灵可以重叠。我知道Box2D冲突API提供了一个单位法向量来帮助解决冲突。然而,这个矢量传达的是方向,而不是大小。因此,我无法确定应该将重叠的sprites移动多远。有人知道如何使用Box2D冲突API手动解决重叠问题吗?
问题内容: 如何检测两个元素是否发生冲突? 这两个div是简单的彩色框,彼此垂直,因此没有复杂的形状或角度。 问题答案: 一般思路-获得框的偏移量和尺寸,并检查它们是否重叠。 如果要更新,可以使用: 另外,请注意,您可以针对特定示例优化功能。 因为它们是固定的,所以您不必重复读取框的尺寸(就像我在代码中一样)。您可以在页面加载时读取它们(将其读取到变量中),然后仅读取变量 小盒子的水平位置不会改变
我正在尝试为我的大学工作制作一个基于2D平台的游戏(在SFML)。我不是要求任何人为我编写一些代码,但如果有人能提供一些指示,我将非常感激:) 目前我有大约13门课,包括: BaseEntity(大多数游戏对象都是由此派生的) 玩家(继承自BE) 魔法宝石(玩家需要这些来通过关卡晋级) 平台 SolidBlock(从平台继承) 可以说,我已经构建了大部分的游戏“积木”--每个类都有自己的更新函数,
我正在尝试制作一个砖块游戏,在碰撞检测方面遇到了一些问题。如果你曾经玩过撞砖游戏,你知道在划桨时,如果球向左移动,而你击中了顶部的左侧,那么它会继续向右移动。不过,在这种情况下,如果你从右侧击球,那么球就会改变方向。而且如果你在桨的侧面撞击它,它会在Y轴上反弹。由于我不知道如何完成桨叶的顶部,我无法向您展示代码,因为我没有任何代码:)这是我用于侧面的代码: 发生的是,当球从侧面被击中时,它正好穿过
在前面的一些章节中,我们介绍了诸多用于图像分类的模型。在图像分类任务里,我们假设图像里只有一个主体目标,并关注如何识别该目标的类别。然而,很多时候图像里有多个我们感兴趣的目标,我们不仅想知道它们的类别,还想得到它们在图像中的具体位置。在计算机视觉里,我们将这类任务称为目标检测(object detection)或物体检测。 目标检测在多个领域中被广泛使用。例如,在无人驾驶里,我们需要通过识别拍摄到