首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AABBs的交叉口改进

AABBs的交叉口改进
EN

Code Review用户
提问于 2018-04-23 15:34:39
回答 2查看 386关注 0票数 5

我试图为定向包围框(OBB)和轴对齐边界框(AABB)编写一些交叉代码。我有OBB-OBB交集,使用分离轴定理(SAT),我正在试图找出如何将这段代码改进到我所知道的比较OBB和AABB的具体情况。

这是我的函数代码:

代码语言:javascript
复制
bool Collider::isColliding(OBB * one, OBB * other)
{
    TestManager::collisionTests++;
    glm::vec3 oneCenter = one->m_gameObject->getWorldPosition(); // object's pos = collider center
    glm::mat4 oneTransform = glm::scale(one->m_gameObject->getTransform(), one->m_halfSize); // scaling for halfsize
    glm::vec3 otherCenter = other->m_gameObject->getWorldPosition();
    glm::mat4 otherTransform = glm::scale(other->m_gameObject->getTransform(), other->m_halfSize);

    for (int a = 0; a < 3; a++) {
        glm::vec3 l = glm::vec3(oneTransform[a]); // one axis to project on
        float tl = std::abs(glm::dot(l, otherCenter) - glm::dot(l, oneCenter)); // center distance
        float ra = std::abs(glm::dot(l, glm::vec3(oneTransform[0]))) + std::abs(glm::dot(l, glm::vec3(oneTransform[1]))) + std::abs(glm::dot(l, glm::vec3(oneTransform[2])));
        float rb = std::abs(glm::dot(l, glm::vec3(otherTransform[0]))) + std::abs(glm::dot(l, glm::vec3(otherTransform[1]))) + std::abs(glm::dot(l, glm::vec3(otherTransform[2])));
        float penetration = (ra + rb) - tl;
        if (penetration <= 0) { // no overlap
            return false;
        }
    }
    for (int b = 0; b < 3; b++) {
        glm::vec3 l = glm::vec3(otherTransform[b]); // other axis to project on
        float tl = std::abs(glm::dot(l, otherCenter) - glm::dot(l, oneCenter)); // center distance
        float ra = std::abs(glm::dot(l, glm::vec3(oneTransform[0]))) + std::abs(glm::dot(l, glm::vec3(oneTransform[1]))) + std::abs(glm::dot(l, glm::vec3(oneTransform[2])));
        float rb = std::abs(glm::dot(l, glm::vec3(otherTransform[0]))) + std::abs(glm::dot(l, glm::vec3(otherTransform[1]))) + std::abs(glm::dot(l, glm::vec3(otherTransform[2])));
        float penetration = (ra + rb) - tl;
        if (penetration <= 0) { // no overlap
            return false;
        }
    }
    for (int a = 0; a < 3; a++) {
        glm::vec3 aAxis = glm::vec3(oneTransform[a]);
        for (int b = 0; b < 3; b++) {
            glm::vec3 bAxis = glm::vec3(otherTransform[b]);
            if (aAxis != bAxis) {
                glm::vec3 l = glm::cross(aAxis, bAxis); // has flaw when axis are same, result in (0,0,0), solved by if
                float tl = std::abs(glm::dot(l, otherCenter) - glm::dot(l, oneCenter)); // center distance
                float ra = std::abs(glm::dot(l, glm::vec3(oneTransform[0]))) + std::abs(glm::dot(l, glm::vec3(oneTransform[1]))) + std::abs(glm::dot(l, glm::vec3(oneTransform[2])));
                float rb = std::abs(glm::dot(l, glm::vec3(otherTransform[0]))) + std::abs(glm::dot(l, glm::vec3(otherTransform[1]))) + std::abs(glm::dot(l, glm::vec3(otherTransform[2])));
                float penetration = (ra + rb) - tl;
                if (penetration <= 0) { // no overlap
                    return false;
                }
            }
        }
    }
    return true;
}

希望你能帮我。

EN

回答 2

Code Review用户

发布于 2018-04-23 19:45:38

宽相位碰撞检测

看起来你是用这个来进行所谓的宽相位碰撞检测。这是碰撞检测中的步骤,用于确定执行实际碰撞检测(快速总结)的狭窄阶段的候选对。

因为这是一个边框文本(特别是如果您涉及到AABB),看起来您只是想看看是否要通过这两个形状的实际交叉口路线。如果你能坚持AABB在一般情况下,数学变得容易得多,因此更快。此外,您还可以使用AABB-树(它们是空间部分树)来为一个对象查找所有的交叉点候选对象,而不是对一个对象进行配对检查。

票数 4
EN

Code Review用户

发布于 2018-04-23 18:03:55

脑垃圾场:

  • 队伍有点长。我必须不断滚动才能看到整行。虽然现场狭小的空间加剧了这种情况,但其中一些线条确实很长:/
  • 很多注释似乎只是一个借口,不使用正确、显式的变量名。示例一: glm::vec3 3 L=glm::one 3(oneTransform一个);//一个轴来预测下面的内容如何: glm::vec3 3 projectionAxis =glm::vec3 3(oneTransform一个);类似的考虑适用于tlrarb。他们最好分别担任centerDistanceoneProjectedDistanceotherProjectedDistance。(也许也可以考虑radiusOneradiusOther )。关于这一点:a可能就是axis

最后但同样重要的是,我想知道你为什么不在着色器里这样做.

在我(公认的业余)理解着色器基本上是为了快速执行浮点数学,很少分支在GPU上。

这也可能使代码看起来不那么笨重。考虑:

代码语言:javascript
复制
for (int axis = 0; axis < 3; axis++) 
{
    vec3 projectionAxis = oneTransform[axis].xyz;
    float distance = abs(projectionAxis.dot(otherCenter) - projectionAxis.dot(oneCenter));
    float radius_a = abs(projectionAxis.dot(oneTransform[0].xyz)) 
                    + abs(projectionAxis.dot(oneTransform[1].xyz))
                    + abs(projectionAxis.dot(oneTransform[2].xyz));
    // ...

对我来说,这读起来要清晰一些,因为parens更容易理解,并且在一看就可以更容易地掌握所涉及的坐标。

现在,至少我可以更清楚地了解到底发生了什么,我不禁想知道,这是否可以用如下方式来表达:

(免责声明:我只对wolframalpha做了一些快速检查,以确定尺寸是否匹配)

代码语言:javascript
复制
vec3 radius_a_vec = abs(transpose(oneTransform) * projectionAxis);
float radius_a = radius_a_vec.x + radius_a_vec.y + radius_a_vec.z;

这使得数学更难理解,但它极大地简化了对代码的研究。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/192753

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档