自定义 OpenGL OBJ 模型加载器索引计算不起作用

问题描述 投票:0回答:1

我按照这个网站的教程制作了一个简单的模型加载器。

所有坐标都可以很好地读取,但有一点没有涉及到如何计算索引,但在进一步的教程之一中找到这里称为 VBO 索引。虽然这看起来是一个好方法,但它计算的索引是错误的。

我在搅拌机中制作了一个立方体并导出为obj,我用我以前由大学老师制作的obj加载器加载了它,索引读取为0,1,2,3,4,(等等)... 35 为立方体。而索引下方的代码为 0,1,2,3,... 16,17,0,18,3,19,4,6,20,7,9,21,10,12,22,13 ,15,23,16.

这是因为它找到相似的顶点并将其推回到索引,而实际上对于这个立方体不应该有任何相似的索引。

功能索引VBO Slow

void Model::indexVBO_slow(
    std::vector<glm::vec3>& in_vertices,
    std::vector<glm::vec2>& in_uvs,
    std::vector<glm::vec3>& in_normals,

    std::vector<unsigned short>& out_indices,
    std::vector<glm::vec3>& out_vertices,
    std::vector<glm::vec2>& out_uvs,
    std::vector<glm::vec3>& out_normals
) {
    // For each input vertex
    for (unsigned int i = 0; i < in_vertices.size(); i++) {

        // Try to find a similar vertex in out_XXXX
        unsigned short index;
        bool found = getSimilarVertexIndex(in_vertices[i], in_uvs[i], in_normals[i], out_vertices, out_uvs, out_normals, index);

        if (found) { // A similar vertex is already in the VBO, use it instead !
            out_indices.push_back(index);
        }
        else { // If not, it needs to be added in the output data.
            out_vertices.push_back(in_vertices[i]);
            out_uvs.push_back(in_uvs[i]);
            out_normals.push_back(in_normals[i]);
            out_indices.push_back((unsigned short)out_vertices.size() - 1);
        }
    }
}

我将从文件中读取的顶点、uv 和法线传入到一个由 vector3 和 vector2 组成的向量中。其他人则喊出_作为空容器进去。

函数 getSimilarVertexIndex

// Searches through all already-exported vertices
// for a similar one.
// Similar = same position + same UVs + same normal
bool Model::getSimilarVertexIndex(glm::vec3& in_vertex, glm::vec2& in_uv, glm::vec3& in_normal, std::vector<glm::vec3>& out_vertices, std::vector<glm::vec2>& out_uvs, std::vector<glm::vec3>& out_normals, unsigned short& result)
{
    // Lame linear search
    for (unsigned int i = 0; i < out_vertices.size(); i++)
    {
        if (
            is_near(in_vertex.x, out_vertices[i].x) &&
            is_near(in_vertex.y, out_vertices[i].y) &&
            is_near(in_vertex.z, out_vertices[i].z) &&
            is_near(in_uv.x, out_uvs[i].x) &&
            is_near(in_uv.y, out_uvs[i].y) &&
            is_near(in_normal.x, out_normals[i].x) &&
            is_near(in_normal.y, out_normals[i].y) &&
            is_near(in_normal.z, out_normals[i].z)
            )
        {
            result = i;
            return true;
        }
    }

    // No other vertex could be used instead.
    // Needs to be added to VBO
    return false;
}

函数 is_near

bool Model::is_near(float v1, float v2) {
    return fabs(v1 - v2) < 0.01f;
}

填写EBO

// Fill EBO with indices 
m_buffer->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO); //gl bind buffer
m_buffer->FillBuffer(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), &indices[0], GL_STATIC_DRAW); //gl buffer data

我 100% 确定这不起作用的原因是我不完全理解从 obj 中获取数据并将其转换为 OpenGL 索引之间的逻辑。我理解它检查是否已经找到某些数据的部分,以便它可以重用某些索引数据,但不是 if 语句的详细信息。也许是因为我将其作为 EBO 发送,并且教程正在执行 VBO 索引。

解析器代码加上 VBO 索引

std::vector <glm::vec3> m_vertices, m_normals;
std::vector <glm::vec2> m_uvs;

std::vector <unsigned int> vertexIndices, uvIndices, normalIndices;

std::vector<unsigned short> out_indices;
std::vector<glm::vec3> out_vertices;
std::vector<glm::vec2> out_uvs;
std::vector<glm::vec3> out_normals;

std::vector<glm::vec3> temp_vertices, temp_normals;
std::vector<glm::vec2> temp_uvs;

    
std::string temp_text = "";
FILE* file = fopen(filepath.c_str(), "r");

// Open File

if (!file)
{
    TheDebug::Log("Impossible to openfile", ALERT);
    return false;
}

// Read file until the end
while (1)
{
    char lineHeader[128];
    // read the first word of the line
    int res = fscanf(file, "%s", lineHeader);
    
    if (res == EOF)
    {
        break;
    }
    
    // Parse line header
    int x = strcmp(lineHeader, "v");
    if (strcmp(lineHeader, "v") == 0) 
    {
        glm::vec3 vertex;
        fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
        temp_vertices.push_back(vertex);
    }
    // Scan for UVs
    else if (strcmp(lineHeader, "vt") == 0) 
    {
        glm::vec2 uv;
        glm::vec2 uv2;
        glm::vec2 uv3;
        fscanf(file, "%f %f %f %f\n", &uv.x, &uv.y, &uv3.x, &uv2.y);
        temp_uvs.push_back(uv);
    }
    // Scan for normals
    else if (strcmp(lineHeader, "vn") == 0) {
        glm::vec3 normal;
        fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
        temp_normals.push_back(normal);
    }
    // Scan for faces
    else if (strcmp(lineHeader, "f") == 0) 
    {

        std::string vertex1, vertex2, vertex3;
        unsigned int vertexIndex[4], uvIndex[4], normalIndex[4];
        int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2]);
        
        if (matches != 9)
        {
            printf("File can't be read : ( Try exporting with other options\n");
            fclose(file);
            return false;
        }


        // Triangulated
        if (matches == 9)
        {
            //Add 3 total vertices
            m_totalVertices += 3;

            vertexIndices.push_back(vertexIndex[0]);
            vertexIndices.push_back(vertexIndex[1]);
            vertexIndices.push_back(vertexIndex[2]);
            uvIndices.push_back(uvIndex[0]);
            uvIndices.push_back(uvIndex[1]);
            uvIndices.push_back(uvIndex[2]);
            normalIndices.push_back(normalIndex[0]);
            normalIndices.push_back(normalIndex[1]);
            normalIndices.push_back(normalIndex[2]);
        }
    }
}

// Go through each vertex of each triangle
for (unsigned int i = 0; i < vertexIndices.size(); i++)
{
    unsigned int vertexIndex = vertexIndices[i];
    unsigned int uvIndex = uvIndices[i];
    unsigned int normalIndex = normalIndices[i];

    glm::vec3 vertex = temp_vertices[vertexIndex - 1];
    glm::vec2 uv = temp_uvs[uvIndex - 1];
    glm::vec3 normal = temp_normals[normalIndex - 1];
    m_normals.push_back(normal);

    m_vertices.push_back(vertex);
    m_uvs.push_back(uv);
}

fclose(file);
unsigned short result;

std::vector<GLuint> indices;
std::vector<glm::vec3> indexed_vertices;
std::vector<glm::vec2> indexed_uvs;
std::vector<glm::vec3> indexed_normals;

indexVBO(m_vertices, m_uvs, m_normals, indices, indexed_vertices, indexed_uvs, indexed_normals);

// After I fill buffers with the these indices.

加载Cube的图片

我从昨天开始就在寻找这些信息的来源,但我能找到的地方似乎相当有限,而且没有什么能真正帮助我找到信息,所以我不得不求助于堆栈溢出。

请记住,问题在于计算索引,因为使用另一个模型加载器时,索引是不同的,并且同时从 0 到 35,而我的则不然。

c++ opengl indices
1个回答
0
投票

经过长达 4 天的测试,我发现我可以在 for 循环中将 v3 的向量转换为 GLfloats 的向量,以将它们全部相加,并添加每个 i 的索引。

std::vector<GLfloat> testv;
std::vector<GLfloat> testu;
std::vector<GLfloat> testn;
for (size_t i = 0; i < m_vertices.size(); i++)
{
    testv.push_back(m_vertices[i].x);
    testv.push_back(m_vertices[i].y);
    testv.push_back(m_vertices[i].z);

    testu.push_back(m_uvs[i].x);
    testu.push_back(m_uvs[i].y);

    testn.push_back(m_normals[i].x);
    testn.push_back(m_normals[i].y);
    testn.push_back(m_normals[i].z);
    testindices.push_back(i);
}

这似乎适用于我使用的至少 3 个三角模型,但不知道这是否是最好的方法。

© www.soinside.com 2019 - 2024. All rights reserved.