Loaded OBJ Model Will Not Display in OpenGL / C++ Project
Posted
by
Drake Summers
on Game Development
See other posts from Game Development
or by Drake Summers
Published on 2014-04-02T20:00:03Z
Indexed on
2014/06/02
21:50 UTC
Read the original article
Hit count: 296
I have been experimenting with new effects in game development. The programs I have written have been using generic shapes for the visuals. I wanted to test the effects on something a bit more complex, and wrote a resource loader for Wavefront OBJ files. I started with a simple cube in blender, exported it to an OBJ file with just vertices and triangulated faces, and used it to test the resource loader.
I could not get the mesh to show up in my application. The loader never gave me any errors, so I wrote a snippet to loop through my vertex and index arrays that were returned from the loader. The data is exactly the way it is supposed to be. So I simplified the OBJ file by editing it directly to just show a front facing square. Still, nothing is displayed in the application.
And don't worry, I did check to make sure that I decreased the value of each index by one while importing the OBJ.
-
BEGIN EDIT
I also tested using glDrawArrays(GL_TRIANGLES, 0, 3 );
to draw the first triangle and it worked! So the issue could be in the binding of the VBO/IBO items.
END EDIT
-
INDEX/VERTEX ARRAY OUTPUT:
GLOBALS AND INITIALIZATION FUNCTION:
GLuint program;
GLint attrib_coord3d;
std::vector<GLfloat> vertices;
std::vector<GLushort> indices;
GLuint vertexbuffer, indexbuffer;
GLint uniform_mvp;
int initialize()
{
if (loadModel("test.obj", vertices, indices))
{
GLfloat myverts[vertices.size()];
copy(vertices.begin(), vertices.end(), myverts);
GLushort myinds[indices.size()];
copy(indices.begin(), indices.end(), myinds);
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(myverts), myverts, GL_STATIC_DRAW);
glGenBuffers(1, &indexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, indexbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(myinds), myinds, GL_STATIC_DRAW);
// OUTPUT DATA FROM NEW ARRAYS TO CONSOLE
// ERROR HANDLING OMITTED FOR BREVITY
}
GLint link_result = GL_FALSE;
GLuint vert_shader, frag_shader;
if ((vert_shader = create_shader("tri.v.glsl", GL_VERTEX_SHADER)) == 0) return 0;
if ((frag_shader = create_shader("tri.f.glsl", GL_FRAGMENT_SHADER)) == 0) return 0;
program = glCreateProgram();
glAttachShader(program, vert_shader);
glAttachShader(program, frag_shader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &link_result);
// ERROR HANDLING OMITTED FOR BREVITY
const char* attrib_name;
attrib_name = "coord3d";
attrib_coord3d = glGetAttribLocation(program, attrib_name);
// ERROR HANDLING OMITTED FOR BREVITY
const char* uniform_name;
uniform_name = "mvp";
uniform_mvp = glGetUniformLocation(program, uniform_name);
// ERROR HANDLING OMITTED FOR BREVITY
return 1;
}
RENDERING FUNCTION:
glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0, 0.0, -4.0));
glm::mat4 view = glm::lookAt(glm::vec3(0.0, 0.0, 4.0), glm::vec3(0.0, 0.0, 3.0), glm::vec3(0.0, 1.0, 0.0));
glm::mat4 projection = glm::perspective(45.0f, 1.0f*(screen_width/screen_height), 0.1f, 10.0f);
glm::mat4 mvp = projection * view * model;
int size;
glUseProgram(program);
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnableVertexAttribArray(attrib_coord3d);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(attrib_coord3d, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuffer);
glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
glDrawElements(GL_TRIANGLES, size/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);
glDisableVertexAttribArray(attrib_coord3d);
VERTEX SHADER:
attribute vec3 coord3d;
uniform mat4 mvp;
void main(void)
{
gl_Position = mvp * vec4(coord3d, 1.0);
}
FRAGMENT SHADER:
void main(void)
{
gl_FragColor[0] = 0.0;
gl_FragColor[1] = 0.0;
gl_FragColor[2] = 1.0;
gl_FragColor[3] = 1.0;
}
OBJ RESOURCE LOADER:
bool loadModel(const char * path, std::vector<GLfloat> &out_vertices, std::vector<GLushort> &out_indices)
{
std::vector<GLfloat> temp_vertices;
std::vector<GLushort> vertexIndices;
FILE * file = fopen(path, "r");
// ERROR HANDLING OMITTED FOR BREVITY
while(1)
{
char lineHeader[128];
int res = fscanf(file, "%s", lineHeader);
if (res == EOF) { break; }
if (strcmp(lineHeader, "v") == 0)
{
float _x, _y, _z;
fscanf(file, "%f %f %f\n", &_x, &_y, &_z );
out_vertices.push_back(_x);
out_vertices.push_back(_y);
out_vertices.push_back(_z);
}
else if (strcmp(lineHeader, "f") == 0)
{
unsigned int vertexIndex[3];
int matches = fscanf(file, "%d %d %d\n", &vertexIndex[0], &vertexIndex[1], &vertexIndex[2]);
out_indices.push_back(vertexIndex[0] - 1);
out_indices.push_back(vertexIndex[1] - 1);
out_indices.push_back(vertexIndex[2] - 1);
}
else
{
...
}
}
// ERROR HANDLING OMITTED FOR BREVITY
return true;
}
I can edit the question to provide any further info you may need. I attempted to provide everything of relevance and omit what may have been unnecessary.
I'm hoping this isn't some really poor mistake, because I have been at this for a few days now. If anyone has any suggestions or advice on the matter, I look forward to hearing it.
As a final note:
I added some arrays into the code with manually entered data, and was able to display meshes by using those arrays instead of the generated ones. I do not understand!
© Game Development or respective owner