在旋转/平移对象后重新计算AABB

时间:2012-09-01 09:05:38

标签: c++ opengl collision-detection physics-engine aabb

我在这里看过这个话题,但它并没有真正帮助我解决问题:(我试图以相同的方式实现代码,但有些东西不能正常工作。不幸的是我不能使用glLoadIdentity(),因为我正在使用libqglviewer,并且由于一些奇怪的原因,如果我使用glLoadIdentity(),对象(常规立方体)消失:(所以我的解决方法是我使用glPopMatrix和glPushMatrix来保持世界矩阵每次完整我必须翻译/旋转一个物体。原始矩阵被存储起来,然后一旦完成平移/旋转,我再次将它弹回。

到目前为止一直运行良好,但是一旦我尝试实现重新计算边界框,我的框开始于与立方体相同的位置但是一旦我开始旋转它,边界框有时会“内爆”因此我需要检查最大/最小角落,使它们不会小于立方体本身,但是当我旋转相机时,边界框会移动到一侧或另一侧。

我正在使用GLM来加载模型,遗憾的是Legacy OpenGL,我对Legacy OGL的工作方式有些熟悉,但是当我重新计算边界框的计算时,我认为这是不正确的。

此代码位于我的渲染函数中:

glPushMatrix();
  glTranslatef(position.x, position.y, position.z);
  glRotatef(m_angle, m_torque.x, m_torque.y, m_torque.z);
  glGetFloatv(GL_MODELVIEW_MATRIX, mvMatrix);
  glmDraw(pModelCube, GLM_SMOOTH); // Renders the object
glPopMatrix();

glPushMatrix();
  glTranslatef(position.x, position.y, position.z);
  bb->RecalculateBox(pModelCube, mvMatrix, BBid);
  bb->DrawBox(bb->GetBoundingBox(BBid)); 
glPopMatrix();

这是我设置边界框的代码:

void AABB::initBox(BoundingBox* b)
{
    b->min.x = 10000.0f;
    b->min.y = 10000.0f;
    b->min.z = 10000.0f;

    b->max.x = -10000.0f;
    b->max.y = -10000.0f;
    b->max.z = -10000.0f;
}

BoundingBox* AABB::CreateCollisionBox(GLMmodel* model, GLMgroup* object)
{
    BoundingBox* box = (BoundingBox*)malloc(sizeof(BoundingBox));
    initBox(box);

    for(int i = 0; i < object->numtriangles; i++)
    {
        for(int j = 0; j < 3; j++)
        {
            GLuint index = model->triangles[object->triangles[i]].vindices[j];
            GLfloat x = model->vertices[index*3 + 0];
            GLfloat y = model->vertices[index*3 + 1];
            GLfloat z = model->vertices[index*3 + 2];

            if(box->min.x > x) box->min.x = x;
            if(box->min.y > y) box->min.y = y;
            if(box->min.z > z) box->min.z = z;

            if(box->max.x < x) box->max.x = x;
            if(box->max.y < y) box->max.y = y;
            if(box->max.z < z) box->max.z = z;
        }
    }

    return box;
}

void AABB::DrawBox(BoundingBox* b)
{
    if(collision)
    {
        // Sets color to red
        glColor3f(1.0f, 0.0f, 0.0f);
    }
    else
    {
        // Sets color to yellow
        glColor3f(1.0f, 1.0f, 0.0f);
    }

    glBegin(GL_LINE_LOOP);
    glVertex3f(b->max.x, b->max.y, b->min.z);
    glVertex3f(b->min.x, b->max.y, b->min.z);
    glVertex3f(b->min.x, b->min.y, b->min.z);
    glVertex3f(b->max.x, b->min.y, b->min.z);
    glEnd();

    glBegin(GL_LINE_LOOP);
    glVertex3f(b->max.x, b->min.y, b->max.z);
    glVertex3f(b->max.x, b->max.y, b->max.z);
    glVertex3f(b->min.x, b->max.y, b->max.z);
    glVertex3f(b->min.x, b->min.y, b->max.z);
    glEnd();

    glBegin(GL_LINE_LOOP);
    glVertex3f(b->max.x, b->max.y, b->min.z);
    glVertex3f(b->max.x, b->max.y, b->max.z);
    glVertex3f(b->min.x, b->max.y, b->max.z);
    glVertex3f(b->min.x, b->max.y, b->min.z);
    glEnd();

    glBegin(GL_LINE_LOOP);
    glVertex3f(b->max.x, b->min.y, b->max.z);
    glVertex3f(b->min.x, b->min.y, b->max.z);
    glVertex3f(b->min.x, b->min.y, b->min.z);
    glVertex3f(b->max.z, b->min.y, b->min.z);
    glEnd();
}

最后一篇文章是我重新计算框的地方:

void AABB::RecalculateBox(GLMmodel* model, float matrix[16], int &id)
{
    BoundingBox* box = boxes[id]/*(BoundingBox*)malloc(sizeof(BoundingBox))*/;
    initBox(box);
    float   dimensions[3];

    // This will get the absolute dimensions of the object
    glmDimensions(model, dimensions);

    box->max.x = dimensions[0] / 2.0f, box->min.x = -1.0f * box->max.x;
    box->max.y = dimensions[1] / 2.0f, box->min.y = -1.0f * box->max.y;
    box->max.z = dimensions[2] / 2.0f; box->min.z = -1.0f * box->max.z;

    box->max.x = matrix[0] * box->max.x + matrix[4] * box->max.y + matrix[8] * box->max.z + matrix[12];
    box->max.y = matrix[1] * box->max.x + matrix[5] * box->max.y + matrix[9] * box->max.z + matrix[13];
    box->max.z = matrix[2] * box->max.x + matrix[6] * box->max.y + matrix[10] * box->max.z + matrix[14];
    box->min.x = matrix[0] * box->min.x + matrix[4] * box->min.y + matrix[8] * box->min.z + matrix[12];
    box->min.y = matrix[1] * box->min.x + matrix[5] * box->min.y + matrix[9] * box->min.z + matrix[13];
    box->min.z = matrix[2] * box->min.x + matrix[6] * box->min.y + matrix[10] * box->min.z + matrix[14];

    box->bounds[0] = Vec(box->max.x, box->max.y, box->min.z);
    box->bounds[1] = Vec(box->min.x, box->max.y, box->min.z);
    box->bounds[2] = Vec(box->min.x, box->min.y, box->min.z);
    box->bounds[3] = Vec(box->max.x, box->min.y, box->min.z);
    box->bounds[4] = Vec(box->max.x, box->min.y, box->max.z);
    box->bounds[5] = Vec(box->max.x, box->max.y, box->max.z);
    box->bounds[6] = Vec(box->min.x, box->max.y, box->max.z);
    box->bounds[7] = Vec(box->min.x, box->min.y, box->max.z);

    //This code below is from how my bounding box was calculated before.
    /*for(int i = 0; i < object->numtriangles; i++)
    {
        for(int j = 0; j < 3; j++)
        {
            GLuint index = model->triangles[object->triangles[i]].vindices[j];
            GLfloat x = model->vertices[index*3 + 0];
            GLfloat y = model->vertices[index*3 + 1];
            GLfloat z = model->vertices[index*3 + 2];

            if(box->min.x > x) box->min.x = x;
            if(box->min.y > y) box->min.y = y;
            if(box->min.z > z) box->min.z = z;

            if(box->max.x < x) box->max.x = x;
            if(box->max.y < y) box->max.y = y;
            if(box->max.z < z) box->max.z = z;
        }
    }*/

    boxes[id] = box;
}

我一直在尝试关注这篇文章How to recalculate axis-aligned bounding box after translate/rotate?,但尚未设法使用上面的代码。

关于我出错的地方的任何指示都会有所帮助。

1 个答案:

答案 0 :(得分:1)

  1. 您应该使用库或编写自己的函数进行向量矩阵乘法,手动执行此操作很容易出错(如此处所示)。
  2. 当与矩阵相乘时,您将覆盖矢量分量,同时仍需要旧的值进行读取(例如box-&gt; max.x)。您应该将结果存储在一个新框中(boxTransformed)(一旦完成,您可以根据需要复制回旧框。)
  3. 转换后,您应该采用boxTransformed的max和min-vectors的分量最大值和最小值来生成新的边界框。