I was recently trying to import a mesh in my OpenGL application when I ran across a problem. The mesh imports successfully, however when being rendered it appears completely disfigured. It looks to me that the vertex positions of the mesh were not loaded correctly. Below is an image of what the issue looks like. NOTE: The .obj being imported here is the default monkey mesh from Blender. It can be seen that the general outline of the mesh is kept, however, it is completely off the mark.
I can't ask the best question here, as I can't seem to identify at which point the code is failing. There is no build, or runtime errors. My best guess, however, is that the code is failing while loading the mesh. The code below is the loader function.
bool Loader::LoadObject(
std::string objectFP,
std::vector<glm::vec3>& VBD,
std::vector<glm::vec2>& UVBD,
std::vector<glm::vec3>& NBD,
std::vector<unsigned int>& IBD
)
{
Helpers::Log(LOG, "Loading object (" + objectFP + ")...");
std::vector<glm::vec3> VertexData;
std::vector<glm::vec2> UVData;
std::vector<glm::vec3> NormalData;
FILE* file = fopen(objectFP.c_str(), "r");
if (file == 0)
{
Helpers::Error(ERR, L"Failed to load object.");
return false;
}
else
{
while (true)
{
char lineHeader[128] = { 0 };
int res = fscanf(file, "%s", lineHeader);
/* RUN CHECKS */
// End of File (EOF)
if (res == EOF)
{
break;
}
else
{
if (res <= 0)
{
Helpers::Error(ERR, L"(RES) Failed to load object.");
break;
}
else
{
if (strcmp(lineHeader, "v") == 0)
{
glm::vec3 vertex = glm::vec3(0.0f, 0.0f, 0.0f);
// Return value is not needed here, just to get rid of the warning
int out = fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
VertexData.push_back(vertex);
}
else if (strcmp(lineHeader, "vt") == 0)
{
glm::vec2 uv = glm::vec2(0.0f, 0.0f);
int out = fscanf(file, "%f %f\n", &uv.x, &uv.y);
UVData.push_back(uv);
}
else if (strcmp(lineHeader, "vn") == 0)
{
glm::vec3 normal = glm::vec3(0.0f, 0.0f, 0.0f);
int out = fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
NormalData.push_back(normal);
}
else
{
char fillBuffer[1000];
fgets(fillBuffer, 100, file);
}
VBD.reserve(VertexData.size());
UVBD.reserve(UVData.size());
NBD.reserve(NormalData.size());
for (unsigned int i = 0; i < VertexData.size(); i++)
{
VBD.push_back(VertexData[i]);
}
for (unsigned int i = 0; i < UVData.size(); i++)
{
UVBD.push_back(UVData[i]);
}
for (unsigned int i = 0; i < NormalData.size(); i++)
{
NBD.push_back(NormalData[i]);
}
}
}
}
ComputeIndexBuffer(VBD, IBD);
fclose(file);
return true;
}
}
If this is not the problem. The source code is public here.
It might be a problem with the shaders too.
I checked your monkey.obj
from your repo and as i suspected, your mesh isn't triangulated. when exporting from blender. check the box Triangulated Mesh
as shown below to convert your mesh from polygons to triangles since you are interpreting faces as triangles in your importer.
In your ComputeIndexBuffer()
function:
void Loader::ComputeIndexBuffer(std::vector<glm::vec3> VBD, std::vector<unsigned int>& IBD)
{
for (unsigned int i = 0; i < VBD.size() / 3; i++)
{
unsigned int i1 = i * 3;
unsigned int i2 = i * 3 + 1;
unsigned int i3 = i * 3 + 2;
IBD.push_back(i1);
IBD.push_back(i2);
IBD.push_back(i3);
}
}
you are assuming that faces are triangles, while monkey.obj
file containes mainly quads and hence the incorrect rendering. for processing n-gons, you either have to improve your importer or resort to using dedicated importers like assimp
EDIT: to further clarify it, i will show lines from your 'monkey.obj' and a triangulated one:
in the line below:
f 505/553/499 323/353/499 321/349/499 391/427/499
which is the last line from your monkey.obj
, a face is defined (f
at the start of line) with 4 vertices (i.e. a quad) with each vertex containing info about the position/uv-coords/normals; while a triangulated one will have all of its faces defined like this:
f 505/553/942 323/353/942 321/349/942
as your can see, there are three /
groups, hence three vertices and thus a triangle
.