Не могу отобразить модель, загруженную с Assimp - PullRequest
0 голосов
/ 29 октября 2019

В настоящее время я изучаю OpenGL из следующего ресурса .

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

Я попал в секцию , где вы узнаете о загрузке модели с помощью библиотеки Assimp.

Когда я пытаюсь нарисовать модель , на экране появляется только мой фон .

Я попытался отладить класс ModelLoader, чтобы увидеть, что он делает что-то не так (хотя я в основном следовал учебному пособию, я внес некоторые изменения), но мне кажется, что он выполняет свою работу.

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

Я реализовал класс Camera, используя матрицу lookAt, и я обновляю матрицу view, отправленную вершинному шейдеру, используя ее, чтобы я мог свободно перемещаться, если модель была смещена с помощью th. e model матрица. К сожалению, это не проблема.

Вот реализация класса ModelLoader:

#include "ModelLoader.h"

static std::unordered_map<std::string, std::shared_ptr<Texture>> s_LoadedTextures;

static const std::unordered_map<aiTextureType, unsigned int> g_AiTextureTypeUnitMap
(
    {
        { aiTextureType::aiTextureType_DIFFUSE, 0 },
        { aiTextureType::aiTextureType_SPECULAR, 1 },
        { aiTextureType::aiTextureType_EMISSIVE, 2 },
        { aiTextureType::aiTextureType_AMBIENT, 3 },
        { aiTextureType::aiTextureType_HEIGHT, 4 },
    }
);

Model ModelLoader::Load(const std::string& path)
{
    Assimp::Importer importer;
    const aiScene *scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals);
    Model model(path);

    if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
    {
        std::cout << "ERROR ASSIMP " << importer.GetErrorString() << std::endl;
        return model;
    }

    ModelLoader::ProcessNode(model, scene->mRootNode, scene, path);

    return model;
}

void ModelLoader::ProcessNode(Model& model, aiNode* node, const aiScene* scene, const std::string& path)
{
    for (unsigned int i = 0; i < node->mNumMeshes; i++)
    {
        aiMesh* aiMesh = scene->mMeshes[node->mMeshes[i]];
        Mesh mesh = ModelLoader::ProcessMesh(aiMesh, scene, path);
        model.AddMesh(mesh);
    }
    for (unsigned int i = 0; i < node->mNumChildren; i++)
    {
        ModelLoader::ProcessNode(model, node->mChildren[i], scene, path);
    }
}

Mesh ModelLoader::ProcessMesh(aiMesh* aiMesh, const aiScene* scene, const std::string& path)
{
    std::vector<float> vertices;

    for (unsigned int i = 0; i < aiMesh->mNumVertices; i++)
    {
        vertices.push_back(aiMesh->mVertices[i].x);
        vertices.push_back(aiMesh->mVertices[i].y);
        vertices.push_back(aiMesh->mVertices[i].z);
        vertices.push_back(aiMesh->mNormals[i].x);
        vertices.push_back(aiMesh->mNormals[i].y);
        vertices.push_back(aiMesh->mNormals[i].z);
        if (aiMesh->HasTextureCoords(0))
        {
            vertices.push_back(aiMesh->mTextureCoords[0][i].x);
            vertices.push_back(aiMesh->mTextureCoords[0][i].y);
        }
        else
        {
            vertices.push_back(0.0f);
            vertices.push_back(0.0f);
            vertices.push_back(aiMesh->mTangents[i].x);
            vertices.push_back(aiMesh->mTangents[i].y);
            vertices.push_back(aiMesh->mTangents[i].z);
            vertices.push_back(aiMesh->mBitangents[i].x);
            vertices.push_back(aiMesh->mBitangents[i].y);
            vertices.push_back(aiMesh->mBitangents[i].z);
        }
    }

    std::vector<unsigned int> indices;

    for (unsigned int i = 0; i < aiMesh->mNumFaces; i++)
    {
        aiFace face = aiMesh->mFaces[i];
        for (unsigned int j = 0; j < face.mNumIndices; j++)
        {
            indices.push_back(face.mIndices[j]);
        }
    }

    std::shared_ptr<VertexArray> va = std::make_shared<VertexArray>();
    VertexBufferLayout layout;
    layout.Push({ GL_FLOAT, 3, sizeof(float) * 3, GL_FALSE });
    layout.Push({ GL_FLOAT, 3, sizeof(float) * 3, GL_FALSE });
    layout.Push({ GL_FLOAT, 2, sizeof(float) * 2, GL_FALSE });
    layout.Push({ GL_FLOAT, 3, sizeof(float) * 3, GL_FALSE });
    layout.Push({ GL_FLOAT, 3, sizeof(float) * 3, GL_FALSE });

    std::shared_ptr<VertexBuffer> vb = std::make_shared<VertexBuffer>(vertices.data(), sizeof(vertices.data()), layout);
    std::shared_ptr<IndexBuffer> ib = std::make_shared<IndexBuffer>(indices.data(), indices.size());

    va->SetVertexBuffer(vb);
    va->SetIndexBuffer(ib);

    std::shared_ptr<Material> material = std::make_shared<Material>();

    if (scene->HasMaterials())
    {
        aiMaterial* aiMaterial = scene->mMaterials[aiMesh->mMaterialIndex];
        std::vector<std::shared_ptr<Texture>> diffuseMaps = ModelLoader::LoadMaterialTextures(aiMaterial, aiTextureType_DIFFUSE, path);
        std::vector<std::shared_ptr<Texture>> specularMaps = ModelLoader::LoadMaterialTextures(aiMaterial, aiTextureType_SPECULAR, path);
        std::vector<std::shared_ptr<Texture>> emissiveMaps = ModelLoader::LoadMaterialTextures(aiMaterial, aiTextureType_EMISSIVE, path);
        std::vector<std::shared_ptr<Texture>> ambientMaps = ModelLoader::LoadMaterialTextures(aiMaterial, aiTextureType_AMBIENT, path);
        std::vector<std::shared_ptr<Texture>> heightMaps = ModelLoader::LoadMaterialTextures(aiMaterial, aiTextureType_HEIGHT, path);
        material->AddTextures(TextureType::DIFFUSE_MAP, diffuseMaps);
        material->AddTextures(TextureType::SPECULAR_MAP, specularMaps);
        material->AddTextures(TextureType::EMISSIVE_MAP, emissiveMaps);
        material->AddTextures(TextureType::AMBIENT_MAP, ambientMaps);
        material->AddTextures(TextureType::HEIGHT_MAP, heightMaps);
        material->SetShininess(32.0f);
    }

    return Mesh(va, material);
}

std::vector<std::shared_ptr<Texture>> ModelLoader::LoadMaterialTextures(aiMaterial* material, aiTextureType type, const std::string& path)
{
    std::vector<std::shared_ptr<Texture>> textures;
    for (unsigned int i = 0; i < material->GetTextureCount(type); i++)
    {
        aiString name;
        material->GetTexture(type, i, &name);
        std::string texturePath = path.substr(0, path.find_last_of('/')) + '/' + name.C_Str();
        if (s_LoadedTextures.find(texturePath) == s_LoadedTextures.end())
        {
            std::shared_ptr<Texture> texture = std::make_shared<Texture>(texturePath, g_AiTextureTypeUnitMap.at(type));
            textures.push_back(texture);
            s_LoadedTextures.insert(std::unordered_map<std::string, std::shared_ptr<Texture>>::value_type(texturePath, texture));
        }
    }
    return textures;
}

Класс LoaderModel предполагает, что модель и ее текстуры находятся в одном каталоге.

Вот класс Mesh:

#include "Mesh.h"

#include "OGL.h"

#include "uniform/Uniform1i.cpp"
#include "uniform/Uniform1f.cpp"

Mesh::Mesh(std::shared_ptr<VertexArray>& va, std::shared_ptr<Material>& material)
    : m_VertexArray(va), m_Material(material)
{
}


void Mesh::Draw(Shader& shader)
{
    std::unordered_map<TextureType, std::string> textureTypeNameMap
    (
        {
            {TextureType::DIFFUSE_MAP, "diffuse"},
            {TextureType::SPECULAR_MAP, "specular"},
            {TextureType::EMISSIVE_MAP, "emissive"},
        }
    );

    for (auto& it : textureTypeNameMap) {
        const std::vector<std::shared_ptr<Texture>>& textures = m_Material->GetTextures(it.first);
        for (const auto& texture : textures)
        {
            texture->Bind();
            Uniform1i textureUniform("u_Material." + textureTypeNameMap[it.first]);
            textureUniform.SetValues({ (int)texture->GetUnit() });
            shader.SetUniform(textureUniform);
        }
    }

    Uniform1f shininessUniform("u_Material.shininess");
    shininessUniform.SetValues({ m_Material->GetShininess() });
    shader.SetUniform(shininessUniform);

    if (m_VertexArray->GetIndexBuffer()->GetCount())
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
    else
        glDrawArrays(GL_TRIANGLES, 0, m_VertexArray->GetVertexBuffer()->GetSize());
}

Класс Model просто содержит std::vector<Mesh> сеток и вызывает mesh.Draw() для каждой сетки.

Texure класс:

#include "Texture.h"
#include "stb_image/stb_image.h"

Texture::Texture(const std::string& path, unsigned int unit)
    : m_Path(path), m_Unit(unit)
{
    stbi_set_flip_vertically_on_load(1);
    m_Buffer = stbi_load(path.c_str(), &m_Width, &m_Height, &m_channels, 0);

    GLenum format;
    if (m_channels == 1)
        format = GL_RED;
    else if (m_channels == 3)
        format = GL_RGB;
    else if (m_channels == 4)
        format = GL_RGBA;

    GLCALL(glGenTextures(1, &m_RendererID));
    GLCALL(glActiveTexture(GL_TEXTURE0 + unit));
    GLCALL(glBindTexture(GL_TEXTURE_2D, m_RendererID));
    GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
    GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
    GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
    GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
    GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, format, m_Width, m_Height, 0, format, GL_UNSIGNED_BYTE, m_Buffer));
    glGenerateMipmap(GL_TEXTURE_2D);
    GLCALL(glBindTexture(GL_TEXTURE_2D, 0));

    if (m_Buffer)
        stbi_image_free(m_Buffer);
    std::cout << "Texture CREATED: " << m_RendererID << ", " << m_Path << std::endl;
}

Texture::~Texture()
{
    std::cout << "Texture DELETED: " << m_RendererID << ", " << m_Path << std::endl;
    GLCALL(glDeleteTextures(1, &m_RendererID));
}

void Texture::Bind() const
{
    GLCALL(glActiveTexture(GL_TEXTURE0 + m_Unit));
    GLCALL(glBindTexture(GL_TEXTURE_2D, m_RendererID));
}

void Texture::Unbind() const
{
    GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
}

void Texture::Filter(unsigned int filter, unsigned int mode) const
{
    GLCALL(glTexParameteri(GL_TEXTURE_2D, filter, mode));
}

void Texture::Wrap(unsigned int wrap, unsigned int mode) const
{
    GLCALL(glTexParameteri(GL_TEXTURE_2D, wrap, mode));
}

App.cpp (только соответствующие вещи):

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    {
        /* Make the window's context current */
        glfwMakeContextCurrent(window);

        glfwSwapInterval(1);

        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
        {
            std::cout << "Failed to initialize GLAD" << std::endl;
            return -1;
        }

        glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);

        glfwSetCursorPosCallback(window, mouseCallback);
        glfwSetMouseButtonCallback(window, mouseButtonCallback);

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        Shader shader1;
        shader1.Attach(GL_VERTEX_SHADER, "res/shaders/lightning_scene_vs.shader");
        shader1.Attach(GL_FRAGMENT_SHADER, "res/shaders/lightning_scene_fs.shader");
        shader1.Link();
        shader1.Bind();

        Model nanosuit = ModelLoader::Load("res/models/nanosuit/nanosuit.obj");


        /* Loop until the user closes the window */
        while (!glfwWindowShouldClose(window))
        {
            Time::Update();
            processInput(window);

            glClearColor(0.05f, 0.05f, 0.05f, 1.0f);
            renderer.Clear();

            float timeValue = glfwGetTime();

            float radius = 2.0f;
            pointLightPos = glm::vec3(cos(timeValue) * radius, 1.0f, sin(timeValue) * radius);

            glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)SCREEN_WIDTH / (float)SCREEN_HEIGHT, 0.1f, 100.0f);
            UniformMat4f projectionUniform("u_Projection");
            projectionUniform.SetValues(projection);

            glm::mat4 view = camera.GetView();
            UniformMat4f viewUniform("u_View");
            viewUniform.SetValues(view);

            Uniform3f viewPosUniform("u_ViewPos");
            viewPosUniform.SetValues({ camera.GetEye().x, camera.GetEye().y, camera.GetEye().z });

            spotLightPositionUniform.SetValues({ camera.GetEye().x, camera.GetEye().y, camera.GetEye().z });
            shader1.SetUniform(spotLightPositionUniform);

            spotLightDirectionUniform.SetValues({ camera.GetForward().x, camera.GetForward().y, camera.GetForward().z });
            shader1.SetUniform(spotLightDirectionUniform);

            glm::mat4 model = glm::mat4(1.0f);
            model = glm::translate(model, glm::vec3(0.0f, -1.75f, 0.0f));
            model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f));
            UniformMat4f modelUniform("u_Model");
            modelUniform.SetValues(model);

            pointLightPositionUniform.SetValues({ pointLightPos.x, pointLightPos.y, pointLightPos.z });

            shader1.SetUniform(projectionUniform);
            shader1.SetUniform(viewUniform);
            shader1.SetUniform(modelUniform);
            shader1.SetUniform(pointLightPositionUniform);
            shader1.SetUniform(viewPosUniform);
            renderer.Draw(nanosuit, shader1);

            glfwPollEvents();
            glfwSwapBuffers(window);
        }
    }

    glfwTerminate();
    return 0;
}

1 Ответ

0 голосов
/ 30 октября 2019

Я допустил ошибку при вычислении размера вектора вершин, переданного в constructor из VertexBuffer, позже переданного в glBufferData. Я использовал sizeof(vertices.data()) вместо vertices.size() * sizeof(float), так как первый аргумент вернет размер указателя на машине.

...