crin
crin

Reputation: 73

Create AABB on 3D models in OpenGL

I'm trying to create AABB on 3D models in OpenGL. When I use a 3D box.obj where the vertices are all 1.0 I have no issues detecting collision between models. The trouble arises, however, when I use more complex 3D models with different values for the vertices. The complex models are smaller than the box.obj and have vertex values like .18 and .06 so the bounding boxes on them are so large, my engine detects a collisions between the objects when they aren't touching. A solution to this problem is to keep track of the max/min for each x, y, and z axes when reading the model into my game, but I'm having trouble doing so.

Below is my code for reading in models:

bool Model::buffer(string objFile)
{
vector<vec3> locs;
vector<vec2> uvs;
vector<vec3> norms;

vector<VertInd> vertInds;

// Open file for reading
ifstream inFile;
inFile.open(objFile);

string line;

if (inFile.is_open())
{
    // Enter a loop that reads every line iteration from file until file is empty
    while (getline(inFile, line))
    {
        istringstream ss(line);
        string lineLabel;

        // Read a string (the line label) from the line
        ss >> lineLabel;

        if (lineLabel == "v") // Vertices
        {
            float a, b, c;
            ss >> a >> b >> c;
            locs.push_back(vec3(a, b, c));
        }
        else if (lineLabel == "vt") // Texture Coordinates
        {
            float a, b;
            ss >> a >> b;
            uvs.push_back(vec2(a, b));
        }
        else if (lineLabel == "vn") // Vertex Normals
        {
            float a, b, c;
            ss >> a >> b >> c;
            norms.push_back(vec3(a, b, c));
        }
        // Get indices
        else if (lineLabel == "f")
        {
            // do three times
            for (int i = 0; i < 3; i++)
            {
                unsigned int a, b, c;
                char s1, s2;

                // Read int, then char slash
                ss >> a >> s1 >> b >> s2 >> c;

                // Decrement each of the ints by 1
                vertInds.push_back(VertInd{ a - 1, b - 1, c - 1 });
            }
        }

        /* GLfloat min_x, max_x, min_y, max_y, min_z, max_z;

        min_x = max_x = locs[0].x;
        min_y = max_y = locs[0].y;
        min_z = max_z = locs[0].z;

        for (int i = 0; i < locs.size(); i++)
        {
            if (locs[i].x < min_x) min_x = locs[i].x;
            if (locs[i].x > max_x) max_x = locs[i].x;
            if (locs[i].y < min_y) min_y = locs[i].y;
            if (locs[i].y > max_y) max_y = locs[i].y;
            if (locs[i].z < min_z) min_z = locs[i].z;
            if (locs[i].z > max_z) max_z = locs[i].z;
        }
        vec3 size = vec3(max_x - min_x, max_y - min_y, max_z - min_z);
        vec3 center = vec3((min_x + max_x) / 2, (min_y + max_y) / 2, (min_z + max_z) / 2);
        mat4 transform = translate(mat4(1), center) * scale(mat4(1), size);

        mat4 m = camera.camMat * transform;
        glUniformMatrix4fv(2, 1, GL_FALSE, &m[0][0]); */
    }
    // Close the file
    inFile.close();
}

vertCount = vertInds.size();

GLuint vertBuf;

vector<Vertex> vertBufData(vertCount);
for (unsigned int i = 0; i < vertCount; i++)
    vertBufData[i] = { locs[vertInds[i].locInd], uvs[vertInds[i].uvInd], norms[vertInds[i].normInd] };

// Vertex array
glGenVertexArrays(1, &vertArr);
glGenBuffers(1, &vertBuf);

// Buffer data
glBindVertexArray(vertArr);
glBindBuffer(GL_ARRAY_BUFFER, vertBuf);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) *vertCount, &vertBufData[0], GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)sizeof(vec3)); // (void*)sizeof(VertInd));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(vec3) + sizeof(vec2)));
glBindVertexArray(0);

//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

return true;

}

The section commented out /**/ is the part I've recently added in an attempt to get the min/max vert values and center my model, but now the scene won't even load.

Upvotes: 1

Views: 2229

Answers (1)

genpfault
genpfault

Reputation: 52082

See usage example here:

// return the min/max points of pts
template< typename Vec >
pair< Vec, Vec > GetExtents( const Vec* pts, size_t stride, size_t count )
{
    unsigned char* base = (unsigned char*)pts;
    Vec pmin( *(Vec*)base );
    Vec pmax( *(Vec*)base );
    for( size_t i = 0; i < count; ++i, base += stride )
    {
        const Vec& pt = *(Vec*)base;
        pmin = glm::min( pmin, pt );
        pmax = glm::max( pmax, pt );
    }

    return make_pair( pmin, pmax );
}

// centers geometry around the origin
// and scales it to fit in a size^3 box
template< typename Vec > 
void CenterAndScale( Vec* pts, size_t stride, size_t count, const typename Vec::value_type& size )
{
    typedef typename Vec::value_type Scalar;

    // get min/max extents
    pair< Vec, Vec > exts = GetExtents( pts, stride, count );

    // center and scale 
    const Vec center = ( exts.first * Scalar( 0.5 ) ) + ( exts.second * Scalar( 0.5f ) );

    const Scalar factor = size / glm::compMax( exts.second - exts.first );
    unsigned char* base = (unsigned char*)pts;
    for( size_t i = 0; i < count; ++i, base += stride )
    {
        Vec& pt = *(Vec*)base;
        pt = ( ( pt - center ) * factor );
    }    
}

Upvotes: 3

Related Questions