简体   繁体   中英

Recalculating AABB correct after rotation/translation of an object

I've seen this topic around here but it didn't really help me solve the problem :( I've tried to implement the code kinda like the same way but something isn't working properly. Unfortunately I can't use glLoadIdentity() since I'm working with libqglviewer and for some odd reason if I do use glLoadIdentity() the object (a regular cube) disappears :( so my workaround is I use glPopMatrix and glPushMatrix to keep the world matrix intact each time I have to translate/rotate an object. The original matrix is being stored away and then once the translation/rotation is done I pop it right back again.

So far that has worked fine, but once I tried to implement the recalculation of the bounding box my box starts of at the same position as the cube but once I start rotating it the bounding box sometimes "implodes" hence I need to check the max/min corners so they don't get smaller than the cube itself, but when I rotate the camera the bounding box shifts of to one or the other side.

I'm using GLM to load the models and unfortunately Legacy OpenGL, I'm somewhat familiar with how Legacy OGL works but something isn't right with the calculations of the bounding box when it is recalculated I think.

This code is in my render function:

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();

This is my code for setting up the bounding box:

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();
}

This final piece is where I recalculate the box:

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;
}

I've been trying to follow this post How to recalculate axis-aligned bounding box after translate/rotate? but haven't managed to get it to work with my code above.

Any pointers as to where I'm going wrong would be helpful.

  1. You should use a library or write own functions for vector-matrix multiply, doing this by hand is easily error-prone (as here).
  2. When multiplying with the matrix, you overwrite your vector-components while you still need the old value for reading (eg box->max.x). You should store the results in a new box (boxTransformed) instead (once your done, you can copy back to the old one if you want to).
  3. After the transformation, you should take the componentwise maximum and minimum of boxTransformed's max and min-vectors to generate the new bounding box.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM