I'm trying to setup a simple OpenGL framework for a project and I'm running into a problem displaying my .obj model object. From what I can tell, the object is being loaded in fine using assimp
, and all it's meshes should be drawn onto the screen but I'm not seeing anything..
I'll walk you through the whole process from loading the .obj all the way to where I draw it. First lets get some need to know files out of the way:
main.cxx
int main()
{
Display display(800, 600, "project2");
Model model("./models/nanosuit/nanosuit.obj");
Shader shader("./shaders/shader");
Texture texture("./textures/wall.jpg");
int width, height;
glfwGetWindowSize(display.GetWindow(), &width, &height);
Camera camera(glm::vec3(0, 0, -5.0f), 45.0f, (float)width/height, 0.1f, 1000.0f);
Transform transform;
while (!display.IsClosed())
{
display.ProcessInput();
display.Clear(0.0f, 0.15f, 0.3f, 1.0f);
shader.Bind();
texture.Bind(0);
shader.Update(transform, camera);
model.Draw();
display.Update();
}
return 0;
}
Shader::Update()
void Shader::Update(const Transform& transform, const Camera& camera)
{
glm::mat4 trans = camera.GetViewProjection() * transform.GetModel();
glUniformMatrix4fv(uniforms[TRANSFORM_U], 1, GL_FALSE, &trans[0][0]);
}
vertex shader
#version 330 core
layout (location=0) in vec3 position;
layout (location=1) in vec2 texCoord;
layout (location=2) in vec3 normal;
out vec2 texCoord0;
out vec3 normal0;
uniform mat4 transform;
void main() {
gl_Position = transform * vec4(position, 1.0);
texCoord0 = texCoord;
normal0 = (transform * vec4(normal, 0.0)).xyz;
}
fragment shader
#version 330 core
out vec4 FragColor;
uniform sampler2D diffuse;
in vec2 texCoord0;
in vec3 normal0;
void main() {
FragColor = texture(diffuse, texCoord0);
}
I start by loading the model in my Model class's constructor
Model model("./models/nanosuit/nanosuit.obj");
model.cxx
Model::Model(const std::string& filePath)
{
Assimp::Importer import;
const aiScene *scene = import.ReadFile(filePath, aiProcess_Triangulate | aiProcess_FlipUVs);
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
std::cout << "ERROR::ASSIMP::" << import.GetErrorString() << std::endl;
return;
}
//directory = filePath.substr(0, filePath.find_last_of('/'));
processNode(scene->mRootNode, scene);
}
void Model::Draw()
{
for (unsigned int i = 0; i < meshes.size(); ++i)
meshes[i].Draw();
}
void Model::processNode(aiNode *node, const aiScene *scene)
{
for (unsigned int i = 0; i < node->mNumMeshes; ++i)
{
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(processMesh(mesh, scene));
}
for (unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(node->mChildren[i], scene);
}
}
Mesh Model::processMesh(aiMesh *mesh, const aiScene *scene)
{
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
for (unsigned int i = 0; i < mesh->mNumVertices; ++i)
{
glm::vec3 position = glm::vec3(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z);
glm::vec2 texCoords = glm::vec2(0.0f);
if(mesh->mTextureCoords[0])
texCoords = glm::vec2(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y);
glm::vec3 normal = glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
Vertex vertex(position, texCoords, normal);
vertices.push_back(vertex);
}
// process indices
for(unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for(unsigned int j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
return Mesh(&vertices[0], vertices.size(), &indices[0], indices.size());
}
This in turn creates a list of meshes, which are then drawn on screen by calling
Model::Draw()
For your reference here is my mesh class
mesh.cxx
Mesh::Mesh(Vertex *vertices, unsigned int numVertices, unsigned int* indices, unsigned int numIndices)
{
std::vector<glm::vec3> positions;
std::vector<glm::vec2> texCoords;
std::vector<glm::vec3> normals;
for (unsigned int i = 0; i < numVertices; ++i)
{
positions.push_back(vertices[i].GetPos());
texCoords.push_back(vertices[i].GetTexCoord());
normals.push_back(vertices[i].GetNormal());
}
drawCount = numIndices;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(NUM_BUFFERS, VBO);
// positions
glBindBuffer(GL_ARRAY_BUFFER, VBO[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(positions[0]), &positions[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
// texCoords
glBindBuffer(GL_ARRAY_BUFFER, VBO[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
// normals
glBindBuffer(GL_ARRAY_BUFFER, VBO[NORMAL_VB]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(normals[0]), &normals[0], GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(2);
// indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO[INDEX_VB]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndices * sizeof(indices[0]), &indices[0], GL_STATIC_DRAW);
glBindVertexArray(0);
}
Mesh::~Mesh()
{
glDeleteVertexArrays(1, &VAO);
}
void Mesh::Draw()
{
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
I've verified that the model vertices are in fact received by the Mesh::Draw() method and they should be drawn.. But again no output in the window :(