OBJ Loader не создает и не создает объект - PullRequest
0 голосов
/ 25 января 2020

Я хотел реализовать загрузчик obj, который бы принимал координаты 'v' (вершина), 'vt' (текстура), 'vn' (нормали) и 'f' (лица) из файла obj, экспортированного из blender и сделать это в моей программе. Однако после его реализации я обнаружил, что с ним возникла проблема. Ничто не показывает, когда я его создаю. Теперь, с тех пор как я начал, мой код sh всегда был проблемой для меня, поэтому я надеюсь, что кто-то сможет найти то, что я не могу. Не только это, но и состояния кода текстуры (в терминале), Trying to access the pixels of an empty image. Однако у изображения, которое я даю, есть пиксели, и я абсолютно не знаю, почему это происходит.

// Chest.cpp 
objLoader.loadObjModel("res/models/test.obj");
mesh.loadToVAO(objLoader.getVertices(), objLoader.getTextures(), objLoader.getNormals(), objLoader.getIndices());
mesh.loadTexture(Texture::get("res/images/wallpaper.png"));
program = Program::get(BASIC_VERTEX_SHADER, BASIC_FRAGMENT_SHADER);

Это загружает модель obj из test.obj, а затем в mesh.loadToVAO получает вершины, текстуры, нормали и индексы. Затем me sh также получает текстуру местоположения.

// Mesh.cpp // Loading 
void Mesh::loadToVAO(std::vector<glm::vec3> vertices, std::vector<glm::vec2> textures, std::vector<glm::vec3> normals, std::vector<int> indices) {
    // create a VAO
    GLuint vaoID = createVAO();
    indicesSize = indices.size();
    bindIndicesBuffer(indices.data(), indicesSize);

    // Store the data in attribute lists
    storeDataInAttrubeList(0, 3, &vertices[0], vertices.size() * sizeof(glm::vec3));
    storeDataInAttrubeList(1, 2, &textures[0], textures.size() * sizeof(glm::vec2));
    storeDataInAttrubeList(2, 3, &normals[0], normals.size() * sizeof(glm::vec3));
    unbindVAO();
}

// Rendering
void Mesh::renderVAO() {
    // Texture
    texture->useTexture();

    // Binding
    glBindVertexArray(VAO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO);

    // Rendering
    glDrawElements(GL_TRIANGLES, indicesSize, GL_UNSIGNED_INT, 0);

    // Unbinding
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

// createVAO/storeDataInAttrubeList/bindIndicesBuffer
GLuint Mesh::createVAO() {
    GLuint vaoID;

    glGenVertexArrays(1, &vaoID);
    VAO = vaoID;
    glBindVertexArray(vaoID);

    return vaoID;
}

void Mesh::storeDataInAttrubeList(GLuint attribNumber, int attribSize, void* data, int dataSize) {
    GLuint vboID;
    // Create a new buffer
    glGenBuffers(1, &vboID);
    // Store the buffer in the list
    VBO = vboID;
    // Bind the buffer to use it
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    // Store the data in the buffer
    glBufferData(GL_ARRAY_BUFFER, dataSize, data, GL_STATIC_DRAW);
    // Tell OpenGL how and where to store this VBO in the VAO
    glVertexAttribPointer(attribNumber, attribSize, GL_FLOAT, GL_FALSE, 0, nullptr);
}

void Mesh::bindIndicesBuffer(int* indices, int& count) {
    GLuint vboID;
    // Generate a buffer and bind it for use
    glGenBuffers(1, &vboID);
    // Store the buffer in the list
    VBO = vboID;
    // Bind the buffer to use it
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboID);
    // Store the indices in the buffer
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * count, indices, GL_STATIC_DRAW);
} 

Это проходит через каждую строку и находит соответствующую координату.

while (fgets(line, 256, file) != NULL) {
        token = NULL;
        type = strtok_s(line, " ", &token);

        // Vertex
        if (type[0] == 'v' && type[1] == NULL) {
            x = strtod(token, &stop);
            token = stop + 1; 
            y = strtod(token, &stop);
            token = stop + 1; 
            z = strtod(token, &stop);

            vertices.push_back(glm::vec3(x, y, z));
        }

        // Textures
        else if (type[0] == 'v' && type[1] == 't') {
            x = strtod(token, &stop);
            token = stop + 1; 
            y = 1 - strtod(token, &stop);

            tempTextures.push_back(glm::vec2(x, y));
        }

        // Normals
        else if (type[0] == 'v' && type[1] == 'n') {
            x = strtod(token, &stop);
            token = stop + 1; 
            y = strtod(token, &stop);
            token = stop + 1; 
            z = strtod(token, &stop);

            tempNormals.push_back(glm::vec3(x, y, z));
        }

        // Faces
        else if (type[0] == 'f') {
            if (indices.size() == 0) {
                // Set size of the array
                textures.resize(vertices.size());
                normals.resize(vertices.size());
            }

            // Process vertices data
            processVertices(token, indices, tempTextures, textures, tempNormals, normals);
        }
    }
// This method process the vertice and indice information 
void OBJLoader::processVertices(char* vertexData, std::vector<int>& indices, std::vector<glm::vec2>& tempTextures, 
    std::vector<glm::vec2>& textures, std::vector<glm::vec3>& tempNormals, std::vector<glm::vec3>& normals) {

    char* stop;
    int vertexPointer;

    for (unsigned int i = 0; i < 3; i++) {
        // Get and store index
        vertexPointer = strtol(vertexData, &stop, 10) - 1;
        indices.push_back(vertexPointer);
        vertexData = stop + 1; 

        textures[vertexPointer] = tempTextures[strtol(vertexData, &stop, 10) - 1];
        vertexData = stop + 1; 

        normals[vertexPointer] = tempNormals[strtol(vertexData, &stop, 10) - 1];
        vertexData = stop + 1; 
    }
}

В Chest.cpp вы можете видеть, что я вызываю метод с именем get(something), это как это выглядит

std::vector<glm::vec3> getVertices() { return vertices; } // Note that vertices and etc. are vectors

Итак, наконец, это не рендеринг или просто не создание? Я знаю, что код довольно длинный, однако я точно не знаю, какие части наиболее важны или наиболее ответственны за мою проблему.

1 Ответ

1 голос
/ 25 января 2020

Я не знаю, решит ли это все проблемы в вашем коде, но я заметил несколько вещей:

  1. Mesh::storeDataInAttrubeList() создает новый VBO для каждого массива атрибутов (что возможно в GL, но вам это не нужно. Упакуйте все данные объекта в один VBO). Но что хуже, он перезаписывает переменную (Mesh class?) VBO. Таким образом, вы в основном теряете идентификаторы VBO, которые вы создали ранее. Что еще хуже, вы используете VBO позже в качестве буфера массива элементов при рендеринге, что полностью испортит ваш рендеринг.
  2. Mesh::renderVAO() изменяет привязку буфера элементов и сбрасывает ее на 0 каждый раз , Это не обязательно. Привязка GL_ELEMENT_ARRAY_BUFFER хранится в VAO, нет необходимости устанавливать и сбрасывать ее при каждом вызове отрисовки.
  3. Ваш анализатор OBJ неправильно дублирует вершины. Вам необходимо создать вершину для каждого уникального vertexID/texcoordID/normalID триплета. Но вы просто перезаписываете данные вершин в vertexID новыми текстовыми координатами и нормалями вместо создания совершенно новой вершины.
...