在 OpenGL 中的 3D 模型上创建 AABB

Posted

技术标签:

【中文标题】在 OpenGL 中的 3D 模型上创建 AABB【英文标题】:Create AABB on 3D models in OpenGL 【发布时间】:2017-05-18 19:15:58 【问题描述】:

我正在尝试在 OpenGL 的 3D 模型上创建 AABB。当我使用顶点均为 1.0 的 3D box.obj 时,检测模型之间的碰撞没有问题。然而,当我使用具有不同顶点值的更复杂的 3D 模型时,问题就出现了。复杂模型比 box.obj 小,并且具有 .18 和 .06 之类的顶点值,因此它们上的边界框非常大,我的引擎在它们不接触时检测到对象之间的碰撞。解决此问题的方法是在将模型读入我的游戏时跟踪每个 x、y 和 z 轴的最大/最小值,但我在这样做时遇到了麻烦。

以下是我在模型中读取的代码:

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;

注释掉 /**/ 的部分是我最近添加的部分,试图获取最小/最大顶点值并使模型居中,但现在场景甚至无法加载。

【问题讨论】:

【参考方案1】:

查看用法示例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 );
        

【讨论】:

以上是关于在 OpenGL 中的 3D 模型上创建 AABB的主要内容,如果未能解决你的问题,请参考以下文章

Android上OpenGL ES显示blender 3D字符的方法

我应该如何将 OpenGL 模型视图转换为 CATransform3D?

在 OpenGL 中编程特定的 3d(星形)模型? [关闭]

OpenGL ES之3D模型加载和渲染

如何在opengl中计算给定3D点及其2D屏幕位置的投影/模型视图矩阵

✠OpenGL-6-3D模型