似乎无法渲染加载有Assimp

时间:2019-10-29 17:34:37

标签: c++ opengl glfw assimp

我目前正在从以下resource学习OpenGL。

我正在尝试使用几个地方作为指导来实现自己的抽象中的大多数内容。

我到了section,在这里您了解了如何使用Assimp库加载模型。

当我尝试绘制模型时,只有背景显示在屏幕上

我尝试调试ModelLoader类,看它是否做错了什么(尽管我主要按照本教程进行操作,但是我进行了一些更改) 但在我看来,它正在发挥作用。

我还试图制作一个基本的片段着色器,该片段着色器仅将白色输出到屏幕,而不是使用考虑了所有材质的雷光场景片段着色器。

我已经使用Camera矩阵实现了lookAt类,并使用该矩阵更新了发送到顶点着色器的view矩阵,因此我可以在模型放错地方的情况下自由漫游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 :(得分:0)

在计算传递到constructor的{​​{1}}的顶点矢量的大小时出错,后来又传递给VertexBuffer。我使用glBufferData代替了sizeof(vertices.data()),因为第一个参数将返回机器上指针的大小。