On general my question is how can I provide 2 indices for the vbo. One for the vertices and one for the normals?
I got the next Obj file:
mtllib cube.mtl
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -0.000000 -0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
usemtl Material
f 1//1 2//1 3//1 4//1
f 5//2 8//2 7//2 6//2
f 1//3 5//3 6//3 2//3
f 2//4 6//4 7//4 3//4
f 3//5 7//5 8//5 4//5
f 5//6 1//6 4//6 8//6
As you can see there are 8 vertices and 6 normals. On the faces lines the file connects each vertex to the next vertex by indices and connects the normals too by different indices.
I am trying to draw with cube model with vbo. I have written the following code:
float vertex[] = {1, -1, -1,
1, -1, 1,
-1, -1, 1,
-1, -1, -1,
1, 1, -1,
1, 1, 1,
-1, 1, 1,
-1, 1, -1};
float normals[] = {0, -1, 0,
0, 1, 0,
1, 0, 0,
0, 0, 1,
-1, 0, 0,
0, 0, -1};
int index[] = {0, 1, 2, 3,
4, 7, 6, 5,
0, 4, 5, 1,
1, 5, 6, 2,
2, 6, 7, 3,
4, 0, 3, 8};
GLuint buffer, ind;
int offset = 0;
void vboInit()
{
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) + sizeof(normals), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vertex), vertex); offset+= sizeof(vertex);
glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(normals), normals); offset+= sizeof(normals);
glGenBuffers(1, &ind);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index), index, GL_STATIC_DRAW);
}
void vboDraw()
{
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind);
glNormalPointer(GL_FLOAT, 0, (GLvoid*)(sizeof(vertex)));
glVertexPointer(3, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
for (int i = 0; i < 6; i++)
glDrawElements(GL_TRIANGLE_FAN, 4 + i*4, GL_UNSIGNED_INT, (GLvoid*)(i*4));
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
}
This code uses the indices of the vertices for the normals. Therefore the normals does not loading well and I need different indices to the normals. The question is how can I provide 2 indices for the vbo. One for the vertices and one for the normals?
Short answer it that you can't. But if you want long one:
DrawElements takes indices arrays of vertices. Vertex is not a position; it is assembly of all attributes at once. When you fetching vertex by index, you must take it from the very same index from every attribute array. Good side of indices is that they enables usage of post-TNL cache (however, utilisation of cache depends upon actual indices values) and reduces memory usage.
If your data saved in OBJ-like layout where attribute arrays indexed in independent way, you have to convert your arrays to more friendly representation. Simple approach would be:
Allocate big array[s] so it can hold all vertex data even without indices.
For each triangle, fetch data to new arrays using your independent indices. As the result, your vertices are now don't have independent attributes indices - but they don't have indices at all! You already could draw though - with DrawArrays().
If you want indices, now you can recreate them. Remove duplicates from new vertices arrays (duplicates have entire vertices equal, not only positions), and for each triangle find index of vertex in new array.
Related
I am using glDrawElement() for rendering a plain but the indexing is not working as intended so i am getting an irrelevant object .I have used AAssetmanager for loading the coordinates from a wavefront object file .
here is my code for rendering :
GLushort squareindices[] = {
0 , 1 ,2,
0, 3, 2
};
GLfloat vertexColor[] = {
1.0f, 1.0f , 0.0f,
0.0f , 0.0f , 1.0f,
1.0f, 1.0f , 0.0f,
0.0f , 0.0f , 1.0f,
};
void flatPlain::render(GLuint program) {
if (renderSelf) {
// flatPlainProgram = program;
auto *gens = new programGenerator;
auto *mats = new matrixOperation;
flatPlainProgram = gens->createProgram(vertexplain, fragmentplain);
// LOGE2("%x" , flatPlainProgram);
vertexLocation = glGetAttribLocation(flatPlainProgram, "vertexPosition");
// textureLocation = glGetAttribLocation(flatPlainProgram, "texturecord");
vertexColorlocation = glGetAttribLocation(flatPlainProgram, "vertexColour");
projection = glGetUniformLocation(flatPlainProgram, "projection");
model = glGetUniformLocation(flatPlainProgram, "modelView");
// sampleLocation = glGetUniformLocation(flatPlainProgram, "texture");
mats->perspective(projectionMatrix, (float) fov, (float) w / (float) h, 0.1f, 100.0f);
// if ( image != nullptr)
// loadTexture();
mats->createVolume(modelMatrix);
mats->rotateX(modelMatrix, angle);
mats->translateMatrix(x, y, z, modelMatrix);
glUseProgram(flatPlainProgram);
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, vertexCord);
glEnableVertexAttribArray(vertexLocation);
glVertexAttribPointer(vertexColorlocation, 3, GL_FLOAT, GL_FALSE, 0, vertexColor);
glEnableVertexAttribArray(vertexColorlocation);
glUniformMatrix4fv(projection, 1, GL_FALSE, projectionMatrix);
glUniformMatrix4fv(model, 1, GL_FALSE, modelMatrix);
// glUniform1i(sampleLocation, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, squareindices);
glDeleteProgram(flatPlainProgram);
}
}
I have read the vertices and then rendered it.
my .obj file:
v 0.000000 0.000000 0.000000
v 10.000000 0.000000 0.000000
v 0.000000 0.000000 -10.000000
v 10.000000 0.000000 -10.000000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 1.000000 1.000000
vt 0.000000 1.000000
vn 0.0000 1.0000 0.0000
usemtl None
s off
f 1/1/1 2/2/1 4/3/1 3/4/1
my output:
This are your vertex coordinates
0: ( 0.0, 0.0, 0.0)
1: (10.0, 0.0, 0.0)
2: ( 0.0, 0.0, -10.0)
3: (10.0, 0.0, -10.0)
0 1
+-----+
| |
| |
+-----+
2 3
Triangulate the quad with the following indices:
0, 1, 2, 1, 3, 2
0 1
+-----+ +
| / / |
| / / |
+ +-----+
2 3
I'm attempting to create a cube with an image texture using OpenGL with Google Cardboard for Android. My code is largely based off of Google's demo code here. I can render the black/texture-less cube just fine, but the texture is what has me stuck.
FILES
Here is the .obj file:
mtllib 9c9ab3c3-ea26-4524-88f5-a524b6bb6057.mtl
g Mesh1 Model
usemtl Tile_Hexagon_White
v 2.16011 0 -2.27458
vt -7.08697 8.39536
vn 0 -1 -0
v 1.16011 0 -1.27458
vt -3.80613 4.70441
v 1.16011 0 -2.27458
vt -3.80613 8.39536
f 1/1/1 2/2/1 3/3/1
v 2.16011 0 -1.27458
vt -7.08697 4.70441
f 2/2/1 1/1/1 4/4/1
vt 7.46254 0
vn 1 0 -0
v 2.16011 1 -1.27458
vt 4.1817 3.69094
vt 4.1817 0
f 1/5/2 5/6/2 4/7/2
v 2.16011 1 -2.27458
vt 7.46254 3.69094
f 5/6/2 1/5/2 6/8/2
vt -7.08697 0
vn 0 0 -1
v 1.16011 1 -2.27458
vt -3.80613 3.69094
vt -7.08697 3.69094
f 1/9/3 7/10/3 6/11/3
vt -3.80613 0
f 7/10/3 1/9/3 3/12/3
vt -4.1817 0
vn -1 0 -0
vt -7.46254 3.69094
vt -7.46254 0
f 2/13/4 7/14/4 3/15/4
v 1.16011 1 -1.27458
vt -4.1817 3.69094
f 7/14/4 2/13/4 8/16/4
vt 3.80613 0
vn 0 0 1
vt 7.08697 3.69094
vt 3.80613 3.69094
f 2/17/5 5/18/5 8/19/5
vt 7.08697 0
f 5/18/5 2/17/5 4/20/5
vt 7.08697 4.70441
vn 0 1 -0
vt 3.80613 8.39536
vt 3.80613 4.70441
f 5/21/6 7/22/6 8/23/6
vt 7.08697 8.39536
f 7/22/6 5/21/6 6/24/6
And here is the .mtl file:
newmtl Tile_Hexagon_White
Ka 0.000000 0.000000 0.000000
Kd 0.835294 0.807843 0.800000
Ks 0.330000 0.330000 0.330000
map_Kd 9c9ab3c3-ea26-4524-88f5-a524b6bb6057/Tile_Hexagon_White.jpg
newmtl ForegroundColor
Ka 0.000000 0.000000 0.000000
Kd 0.000000 0.000000 0.000000
Ks 0.330000 0.330000 0.330000
The texture is just a repeating hexagonal pattern that I want to cover the entire cube:
CODE
Load the OBJ file and separate the data into arrays.
I have Vertices_[108], UV_[72], and Indices_[36]. I am confident that the program is functioning properly at this point, but I can provide the values if necessary.
I load the image after:
GLuint texture_id;
glGenTextures(1, &texture_id);
imageNum = texture_id;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, imageNum);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/*I don't really know how this block of code works but it's supposed to Load an image from the asset manager.
* env - the JNIEnv* environment
* java_asset_mgr - AAssetManager for fetching files
* path - the path and name of my texture
*/
jclass bitmap_factory_class =
env->FindClass("android/graphics/BitmapFactory");
jclass asset_manager_class =
env->FindClass("android/content/res/AssetManager");
jclass gl_utils_class = env->FindClass("android/opengl/GLUtils");
jmethodID decode_stream_method = env->GetStaticMethodID(
bitmap_factory_class, "decodeStream",
"(Ljava/io/InputStream;)Landroid/graphics/Bitmap;");
jmethodID open_method = env->GetMethodID(
asset_manager_class, "open", "(Ljava/lang/String;)Ljava/io/InputStream;");
jmethodID tex_image_2d_method = env->GetStaticMethodID(
gl_utils_class, "texImage2D", "(IILandroid/graphics/Bitmap;I)V");
jstring j_path = env->NewStringUTF(path.c_str());
RunAtEndOfScope cleanup_j_path([&] {
if (j_path) {
env->DeleteLocalRef(j_path);
}
});
jobject image_stream =
env->CallObjectMethod(java_asset_mgr, open_method, j_path);
jobject image_obj = env->CallStaticObjectMethod(
bitmap_factory_class, decode_stream_method, image_stream);
env->CallStaticVoidMethod(gl_utils_class, tex_image_2d_method, GL_TEXTURE_2D, 0,
image_obj, 0);
glGenerateMipmap(GL_TEXTURE_2D);
Draw:
//obj_program has a vertex shader and fragment shader attached.
glUseProgram(obj_program_);
std::array<float, 16> target_array = modelview_projection_target_.ToGlArray();
glUniformMatrix4fv(obj_modelview_projection_param_, 1, GL_FALSE,
target_array.data());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, imageNum);
//DRAW
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, Vertices_.data());
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, Uv_.data());
glDrawElements(GL_TRIANGLES, Indices_.size(), GL_UNSIGNED_SHORT,
Indices_.data());
RESULT
I end up with a cube that is oddly textured and I am unsure what is causing it.
I am sure there will be questions so I will do my best to answer and provide any information that will help!
The issue was that my texture needed to be repeated. These two lines were changed from
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
to
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
I am currently following a basic OpenGL tutorial where the goal is to read data from an .OBJ file and then render the model. The tutorial is located here - http://www.opengl-tutorial.org/beginners-tutorials/tutorial-7-model-loading/.
Currently, my program opens the OBJ file specified and parses it using the parsing engine discussed in the tutorial here - http://www.opengl-tutorial.org/beginners-tutorials/tutorial-7-model-loading/#Reading_the_file.
The object I am trying to render is the Cube located on the same tutorial page URL.
I believe my problem lies in my display(void) function. After I execute glutDisplayFunc(display); in my main(), I am presented with a black window, rather than my rendered model.
This is my current display(void) function:
void display(void)
{
GLuint vbo;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3) * 3, &vertices[0], GL_STATIC_DRAW);
glDrawElements(GL_TRIANGLES, vertices.size() * sizeof(glm::vec3) * 3, GL_UNSIGNED_INT, &vertices[0]);
// check OpenGL error
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR)
{
printf("OpenGL error: %u", err);
}
glEnd();
glutSwapBuffers();
}
And here is the data my parser reads in, perhaps it is a parsing issue:
Success: GLEW_OK
Success: Opened OBJ File cube.obj
Read in Vertices: 1.000000, -1.000000, -1.000000
Read in Vertices: 1.000000, -1.000000, 1.000000
Read in Vertices: -1.000000, -1.000000, 1.000000
Read in Vertices: -1.000000, -1.000000, -1.000000
Read in Vertices: 1.000000, 1.000000, -1.000000
Read in Vertices: 0.999999, 1.000000, 1.000001
Read in Vertices: -1.000000, 1.000000, 1.000000
Read in Vertices: -1.000000, 1.000000, -1.000000
Read in texture coordinate: 0.748573, 0.750412
Read in texture coordinate: 0.749279, 0.501284
Read in texture coordinate: 0.999110, 0.501077
Read in texture coordinate: 0.999455, 0.750380
Read in texture coordinate: 0.250471, 0.500702
Read in texture coordinate: 0.249682, 0.749677
Read in texture coordinate: 0.001085, 0.750380
Read in texture coordinate: 0.001517, 0.499994
Read in texture coordinate: 0.499422, 0.500239
Read in texture coordinate: 0.500149, 0.750166
Read in texture coordinate: 0.748355, 0.998230
Read in texture coordinate: 0.500193, 0.998728
Read in texture coordinate: 0.498993, 0.250415
Read in texture coordinate: 0.748953, 0.250920
Read in Normals: 0.000000, 0.000000, -1.000000
Read in Normals: -1.000000, -0.000000, -0.000000
Read in Normals: -0.000000, -0.000000, 1.000000
Read in Normals: -0.000001, 0.000000, 1.000000
Read in Normals: 1.000000, -0.000000, 0.000000
Read in Normals: 1.000000, 0.000000, 0.000001
Read in Normals: 0.000000, 1.000000, -0.000000
Read in Normals: -0.000000, -1.000000, 0.000000
Reached end of file
Out Vertices Size: 234
glGetError() has not produced an error for me once, so I was not able to debug the issue that way.
Any suggestions / input?
None of those commands (including glGetError (...)) are valid between glBegin (...) and glEnd (...). If you move the calls to glGetError to come after glEnd, you should get GL_INVALID_OPERATION one or more times.
Remove glBegin and glEnd, they serve no purpose in this code, and only render the rest of your commands invalid.
Name
glBegin — delimit the vertices of a primitive or a group of like primitives
C Specification
void glBegin( GLenum mode);
Description
[...]
Only a subset of GL commands can be used between glBegin and glEnd. The commands are glVertex, glColor, glSecondaryColor, glIndex, glNormal, glFogCoord, glTexCoord, glMultiTexCoord, glVertexAttrib, glEvalCoord, glEvalPoint, glArrayElement, glMaterial, and glEdgeFlag. Also, it is acceptable to use glCallList or glCallLists to execute display lists that include only the preceding commands. If any other GL command is executed between glBegin and glEnd, the error flag is set and the command is ignored.
Regarding the rest of your code, you should not be generating a new buffer every frame. Do that once during initialization, add a vertex pointer, and change your draw command to glDrawArrays (...):
glDrawArrays (GL_TRIANGLES, 0, vertices.size());
glDrawElements (...) is only to be used if you have an index buffer. Unless I completely misunderstood the structure of your data, vertices is your vertex data, and does not store a list of indices.
Update 1:
After reading the tutorial your question is based on, the following changes are necessary when you load your .obj model:
GLuint buffers [3];
glGenBuffers(3, buffers);
// Position Buffer = 0
glBindBuffer(GL_ARRAY_BUFFER, buffers [0]);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
glVertexPointer (3, GL_FLOAT, 0, NULL);
// ^^^^^^^^^^^^ Sources data from VBO bound to `GL_ARRAY_BUFFER`, so a NULL pointer is OK
glEnableClientState (GL_VERTEX_ARRAY); // Use this array for drawing
// Tex Coords = 1
glBindBuffer (GL_ARRAY_BUFFER, buffers [1]);
glBufferData (GL_ARRAY_BUFFER, uvs.size () * sizeof (glm::vec2), &uvs [0], GL_STATIC_DRAW);
glTexCoordPointer (2, GL_FLOAT, 0, NULL);
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
// Normals = 2
glBindBuffer (GL_ARRAY_BUFFER, buffers [2]);
glBufferData (GL_ARRAY_BUFFER, normals.size () * sizeof (glm::vec3), &normals [0], GL_STATIC_DRAW);
glNormalPointer (GL_FLOAT, 0, NULL);
glEnableClientState (GL_NORMAL_ARRAY);
Keep in mind, once you learn to use shaders, you should stop using functions such as glVertexPointer (...) and glEnableClientState (...). You will be expected to use glVertexAttribPointer (...) and glEnableVertexAttribArray (...) instead.
I wrote the code this way so you can get something up and running immediately, but it's not the modern way of writing GL software.
I created a .obj loader by modifying some code i found online, to parse to .obj file I do the following
int mesh::getMesh(char* inputFile, std::vector<std::vector<glm::vec3>> & out_vertices,std::vector < glm::vec2 > & out_uvs,std::vector < glm::vec3 > & out_normals){
std::cout << "Attempting to load file as model " << inputFile << "\n";
std::vector<std::vector<unsigned int>> vertexIndices, uvIndices, normalIndices;
std::vector<glm::vec3> temp_vertices;
std::vector<glm::vec2> temp_uvs;
std::vector<glm::vec3> temp_normals;
FILE * file = fopen(inputFile, "r");
if( file == NULL ){
std::cout << "Impossible to open the file !\n";
return 0;
}
while( 1 ){
char lineHeader[128];
// read the first word of the line
int res = fscanf(file, "%s", lineHeader);
if (res == EOF)
break; // EOF = End Of File. Quit the loop.
if ( strcmp( lineHeader, "v" ) == 0 ){
glm::vec3 vertex;
fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z );
temp_vertices.push_back(vertex);
}else if ( strcmp( lineHeader, "vt" ) == 0 ){
glm::vec2 uv;
fscanf(file, "%f %f\n", &uv.x, &uv.y );
temp_uvs.push_back(uv);
}else if ( strcmp( lineHeader, "vn" ) == 0 ){
glm::vec3 normal;
fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z );
temp_normals.push_back(normal);
}else if ( strcmp( lineHeader, "f" ) == 0 ){
unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2] );
if (matches != 9){
std::cout << "File can't be read by the parser : ( Try exporting with other options )\n";
return 0;
}
std::vector<unsigned int> vertexTriangle;
vertexTriangle.push_back(vertexIndex[0]);
vertexTriangle.push_back(vertexIndex[1]);
vertexTriangle.push_back(vertexIndex[2]);
vertexIndices.push_back(vertexTriangle);
//uvIndices .push_back(uvIndex[0]);
//uvIndices .push_back(uvIndex[1]);
//uvIndices .push_back(uvIndex[2]);
//std::vector<unsigned int> normalTriangle;
//normalTriangle.push_back(normalIndex[0]);
//normalTriangle.push_back(normalIndex[1]);
//normalTriangle.push_back(normalIndex[2]);
//normalIndices.push_back(normalTriangle);
}
}
for( unsigned int i=0; i<vertexIndices.size(); i++ ){
std::vector<unsigned int> vertexIndexs=vertexIndices[i];
//glm::vec3 vertex0 = temp_vertices[ vertexIndexs[3]-1 ];
glm::vec3 vertex1 = temp_vertices[ vertexIndexs[0]-1 ];
glm::vec3 vertex2 = temp_vertices[ vertexIndexs[1]-1 ];
glm::vec3 vertex3 = temp_vertices[ vertexIndexs[2]-1 ];
std::vector<glm::vec3> vertex;
vertex.push_back(vertex1); vertex.push_back(vertex2); vertex.push_back(vertex3);
out_vertices.push_back(vertex);
}
return 1;
}
I then draw it using
<initialization...>
std::vector<std::vector<glm::vec3>> vertices;
std::vector<glm::vec2> uvs;
std::vector<glm::vec3> normals;
mesh::getMesh("Resources/Models/cube.obj",vertices,uvs,normals);
<window handling and whatnot...>
for (unsigned i=0; i < vertices.size(); i++) {
std::vector<glm::vec3> vertexGroup = vertices[i];
glBegin(GL_TRIANGLES);
glVertex3f(vertexGroup[0].x,vertexGroup[0].y,vertexGroup[0].z);
glVertex3f(vertexGroup[1].x,vertexGroup[1].y,vertexGroup[1].z);
glVertex3f(vertexGroup[2].x,vertexGroup[2].y,vertexGroup[2].z);
glEnd();
}
This works fine for this .obj file
# Blender3D v249 OBJ File: untitled.blend
# www.blender3d.org
mtllib cube.mtl
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.748573 0.750412
vt 0.749279 0.501284
vt 0.999110 0.501077
vt 0.999455 0.750380
vt 0.250471 0.500702
vt 0.249682 0.749677
vt 0.001085 0.750380
vt 0.001517 0.499994
vt 0.499422 0.500239
vt 0.500149 0.750166
vt 0.748355 0.998230
vt 0.500193 0.998728
vt 0.498993 0.250415
vt 0.748953 0.250920
vn 0.000000 0.000000 -1.000000
vn -1.000000 -0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
vn -0.000001 0.000000 1.000000
vn 1.000000 -0.000000 0.000000
vn 1.000000 0.000000 0.000001
vn 0.000000 1.000000 -0.000000
vn -0.000000 -1.000000 0.000000
usemtl Material_ray.png
s off
f 5/1/1 1/2/1 4/3/1
f 5/1/1 4/3/1 8/4/1
f 3/5/2 7/6/2 8/7/2
f 3/5/2 8/7/2 4/8/2
f 2/9/3 6/10/3 3/5/3
f 6/10/4 7/6/4 3/5/4
f 1/2/5 5/1/5 2/9/5
f 5/1/6 6/10/6 2/9/6
f 5/1/7 8/11/7 6/10/7
f 8/11/7 7/12/7 6/10/7
f 1/2/8 2/9/8 3/13/8
f 1/2/8 3/13/8 4/14/8
but when i move onto something more complicated, like A low poly model of a man i took from a free model site as a testbed, its missing a triangle to every face (see screenshots below)
The Cube:
The Humanoid
The man renders fine in blender so it must be how I'm parsing the file?
You need to triangulate the faces in blender while exporting the model to your format. For obj models you always export with normals attached, and the vertices triangulated. You may also need to check "Keep vertex order".
I'm working on a WaveFront .obj Loader and my first goal is to get all the vertices and indices loaded from the following .obj file (displays a cube with curved edges).
# Blender v2.62 (sub 0) OBJ File: 'Cube.blend'
# www.blender.org
o Cube
v 0.900000 -1.000000 -0.900000
v 0.900000 -1.000000 0.900000
v -0.900000 -1.000000 0.900000
v -0.900000 -1.000000 -0.900000
v 0.900000 1.000000 -0.900000
v 0.899999 1.000000 0.900001
v -0.900000 1.000000 0.900000
v -0.900000 1.000000 -0.900000
v 1.000000 -0.900000 -1.000000
v 1.000000 -0.900000 1.000000
v -1.000000 -0.900000 1.000000
v -1.000000 -0.900000 -1.000000
v 1.000000 0.905000 -0.999999
v 0.999999 0.905000 1.000001
v -1.000000 0.905000 1.000000
v -1.000000 0.905000 -1.000000
f 1//1 2//1 3//1
f 1//1 3//1 4//1
f 13//2 9//2 12//2
f 13//2 12//2 16//2
f 5//3 13//3 16//3
f 5//3 16//3 8//3
f 15//4 7//4 8//4
f 15//5 8//5 16//5
f 11//6 15//6 16//6
f 11//6 16//6 12//6
f 14//7 6//7 7//7
f 14//7 7//7 15//7
f 10//8 14//8 11//8
f 14//8 15//8 11//8
f 13//9 5//9 6//9
f 13//9 6//9 14//9
f 9//10 13//10 10//10
f 13//11 14//11 10//11
f 9//12 1//12 4//12
f 9//12 4//12 12//12
f 3//13 11//13 12//13
f 3//14 12//14 4//14
f 2//15 10//15 11//15
f 2//15 11//15 3//15
f 1//16 9//16 10//16
f 1//16 10//16 2//16
f 5//17 8//17 7//17
f 5//17 7//17 6//17
I've loaded all the vertices and the indices in two vectors called verticesVec and indicesVec and I've checked them both (they have all the input in the correct order, verticesVec[0] = 0.9 and indicesVec[0] = 1). I load the vertices in a VertexBufferObject and the indices in a VerticArrayObject together with the shader fields settings.
However, when I'm rendering the cube I get the following image which is not correct. I've rechecked all my code but I can't find the part where I'm going wrong. Has it something to do with the vectors and the size in bytes of the vectors?
The following code is from my Draw/Render method that does all the rendering.
glUseProgram(theProgram);
GLuint modelToCameraMatrixUnif = glGetUniformLocation(theProgram, "modelToCameraMatrix");
GLuint perspectiveMatrixUnif = glGetUniformLocation(theProgram, "cameraToClipMatrix");
glUniformMatrix4fv(perspectiveMatrixUnif, 1, GL_FALSE, glm::value_ptr(cameraToClipMatrix));
glm::mat4 identity(1.0f);
glutil::MatrixStack stack(identity); // Load identity Matrix
// Push for Camera Stuff
glutil::PushStack camera(stack);
stack.Translate(glm::vec3(camX, camY, camZ));
//Push one step further to fix object 1
glutil::PushStack push(stack);
stack.Translate(glm::vec3(0.0f, 0.0f, 3.0f));
// Draw Blender object
glBindVertexArray(this->load.vertexArrayOBject);
glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(stack.Top()));
glDrawElements(GL_TRIANGLES, this->load.indicesVec.size(), GL_UNSIGNED_SHORT, 0);
// Pop camera (call destructor to de-initialize all dynamic memory)
camera.~PushStack();
// Now reset all buffers/programs
glBindVertexArray(0);
glUseProgram(0);
And the initialisation of buffer objects in my .obj loader:
void Loader::generateVertexBufferObjects()
{
// Fils the vertex buffer object with data
glGenBuffers(1, &vertexBufferObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glBufferData(GL_ARRAY_BUFFER, verticesVec.size() * 4, &verticesVec[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Fills the index buffer object with its data
glGenBuffers(1, &indexBufferObject);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesVec.size() * 4, &indicesVec[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void Loader::generateVertexArrayObjects()
{
glGenVertexArrays(1, &vertexArrayOBject);
glBindVertexArray(vertexArrayOBject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
glBindVertexArray(0);
}
You're creating your indexes as unsigned ints, but you're passing to OpenGL that they are of type GL_UNSIGNED_SHORT. The type argument to glDrawElements must match the type of data uploaded to the index buffer.