В настоящее время я изучаю 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;
}