Drawing a Wavefront OBJ cube

Hello everyone,

I have finally finished my Wavefront OBJ parser (sort of), and trying to test a cube shape, which is unfortunately failing for me.

To begin with i only want to draw the cube actual cube, i dont care about textures or normals!

So this is my Wavefront OBJ file:

v -0.307796 0.00433517 0
v 0.299126 0.00433517 0
v 0.299126 0.00433517 0.48337
v -0.307796 0.00433517 0.48337
v -0.307796 0.364153 0.48337
v 0.299126 0.364153 0.48337
v 0.299126 0.364153 0
v -0.307796 0.364153 0

f 7/1/1 3/2/2 2/3/3
f 3/4/4 7/5/5 6/6/6
f 5/7/7 1/8/8 4/9/9
f 1/10/10 5/11/11 8/12/12
f 7/13/13 1/14/14 8/15/15
f 1/16/16 7/17/17 2/18/18
f 3/19/19 5/20/20 4/21/21
f 5/22/22 3/23/23 6/24/24
f 5/25/25 7/26/26 8/27/27
f 7/28/28 5/29/29 6/30/30
f 3/31/31 1/32/32 2/33/33
f 1/34/34 3/35/35 4/36/36

So basically the faces is written in following form: f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 …

Since i only want the index of the vertices (dont care for normals and textures) i save vertices and my indices as:

const Vertex Vertices[] = {
    {-0.307796,0.00433517,0},
    {0.299126,0.00433517,0},
    {0.299126,0.00433517,0.48337},
    {-0.307796,0.00433517,0.48337},
    {-0.307796,0.364153,0.48337},
    {0.299126,0.364153,0.48337},
    {0.299126,0.364153,0},
    {-0.307796,0.364153,0}
};

const GLubyte Indices[] = {
    7, 3, 2, 
    3, 7, 6, 
    5, 1, 4, 
    1, 5, 8, 
    7, 1, 8, 
    1, 7, 2, 
    3, 5, 4, 
    5, 3, 6, 
    5, 7, 8, 
    7, 5, 6, 
    3, 1, 2, 
    1, 3, 4 
};

And all the OpenGL stuff (objective-C):

- (void)setupRenderBuffer {
    glGenRenderbuffers(1, &_colorRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);        
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];    
}

- (void)setupDepthBuffer {
    glGenRenderbuffers(1, &_depthRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, self.frame.size.width, self.frame.size.height);    
}

- (void)setupFrameBuffer {    
    GLuint framebuffer;
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);   
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer);
}

- (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType {
    
    // 1
    NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:@"glsl"];
    NSError* error;
    NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
    if (!shaderString) {
        NSLog(@"Error loading shader: %@", error.localizedDescription);
        exit(1);
    }
    
    // 2
    GLuint shaderHandle = glCreateShader(shaderType);    
    
    // 3
    const char * shaderStringUTF8 = [shaderString UTF8String];    
    int shaderStringLength = [shaderString length];
    glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
    
    // 4
    glCompileShader(shaderHandle);
    
    // 5
    GLint compileSuccess;
    glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
    if (compileSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
        NSString *messageString = [NSString stringWithUTF8String:messages];
        NSLog(@"%@", messageString);
        exit(1);
    }
    
    return shaderHandle;
    
}

- (void)compileShaders {
    
    // 1
    GLuint vertexShader = [self compileShader:@"SimpleVertex" withType:GL_VERTEX_SHADER];
    GLuint fragmentShader = [self compileShader:@"SimpleFragment" withType:GL_FRAGMENT_SHADER];
    
    // 2
    GLuint programHandle = glCreateProgram();
    glAttachShader(programHandle, vertexShader);
    glAttachShader(programHandle, fragmentShader);
    glLinkProgram(programHandle);
    
    // 3
    GLint linkSuccess;
    glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
    if (linkSuccess == GL_FALSE) {
        GLchar messages[256];
        glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
        NSString *messageString = [NSString stringWithUTF8String:messages];
        NSLog(@"%@", messageString);
        exit(1);
    }
    
    // 4
    glUseProgram(programHandle);
    
    // 5
    _positionSlot = glGetAttribLocation(programHandle, "Position");
    _colorSlot = glGetAttribLocation(programHandle, "SourceColor");
    glEnableVertexAttribArray(_positionSlot);
    glEnableVertexAttribArray(_colorSlot);
    
    _projectionUniform = glGetUniformLocation(programHandle, "Projection");
    _modelViewUniform = glGetUniformLocation(programHandle, "Modelview");
}

- (void)setupVBOs {
    
    GLuint vertexBuffer;
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
    
    GLuint indexBuffer;
    glGenBuffers(1, &indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
    
}

- (void)render:(CADisplayLink*)displayLink {
    glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    
    CC3GLMatrix *projection = [CC3GLMatrix matrix];
    float h = 4.0f * self.frame.size.height / self.frame.size.width;
    [projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:4 andFar:10];
    glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);
    
    CC3GLMatrix *modelView = [CC3GLMatrix matrix];
    [modelView populateFromTranslation:CC3VectorMake(sin(CACurrentMediaTime()), 0, -7)];
    _currentRotation += displayLink.duration * 90;
    [modelView rotateBy:CC3VectorMake(_currentRotation, _currentRotation, 0)];
    glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);
    
    // 1
    glViewport(0, 0, self.frame.size.width, self.frame.size.height);
    
    // 2
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
    
    // 3
//    glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
    glDrawElements(GL_TRIANGLES, sizeof(Indices), GL_UNSIGNED_BYTE, 0);
    
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}

So to get back to the actual issue, i do not exactly get what should have looked like a actual cube. It looks like some bits and pieces are missing in terms of connections to vertices.

I have taken a screenshot to show what i am viewing:

[ATTACH=CONFIG]176[/ATTACH]

Your indices start at 1, you should count starting from 0.

I assume that the first in my Wavefront OBJ file is vt0, if thats what you mean? If thats the case i do start with the first indice which is ‘0’.


const Vertex Vertices[] = {     {-0.307796,0.00433517,0},     {0.299126,0.00433517,0},     {0.299126,0.00433517,0.48337},     {-0.307796,0.00433517,0.48337},     {-0.307796,0.364153,0.48337},     {0.299126,0.364153,0.48337},     {0.299126,0.364153,0},     {-0.307796,0.364153,0} };  
const GLubyte Indices[] = {     7, 3, 2,      3, 7, 6,      5, 1, 4,      1, 5, 8,      7, 1, 8,      1, 7, 2,      3, 5, 4,      5, 3, 6,      5, 7, 8,      7, 5, 6,      3, 1, 2,      1, 3, 4  };


Your indices start at 1 and go to 8, you should index from 0 to 7 as your VBO only has 8 vertices in it.

Also, your glVertexAttribPointer calls seem wrong: stride is the size in bytes of one vertex, 3*sizeof(float) for the position, not sizeof(Vertex). I also don’t see color in your buffer.

Is there a way to create a offset? Because the exporting from AC3D creates the values as they are. I see its a problem now…

Vertex
A valid vertex index starts from 1 and matches the corresponding vertex elements of a previously defined vertex list. Each face can contain three or more vertices.
f v1 v2 v3 v4 …

I tested following which was found randomly:

[QUOTE=menzel;1237877]


const Vertex Vertices[] = {     {-0.307796,0.00433517,0},     {0.299126,0.00433517,0},     {0.299126,0.00433517,0.48337},     {-0.307796,0.00433517,0.48337},     {-0.307796,0.364153,0.48337},     {0.299126,0.364153,0.48337},     {0.299126,0.364153,0},     {-0.307796,0.364153,0} };  
const GLubyte Indices[] = {     7, 3, 2,      3, 7, 6,      5, 1, 4,      1, 5, 8,      7, 1, 8,      1, 7, 2,      3, 5, 4,      5, 3, 6,      5, 7, 8,      7, 5, 6,      3, 1, 2,      1, 3, 4  };


Your indices start at 1 and go to 8, you should index from 0 to 7 as your VBO only has 8 vertices in it.

Also, your glVertexAttribPointer calls seem wrong: stride is the size in bytes of one vertex, 3*sizeof(float) for the position, not sizeof(Vertex). I also don’t see color in your buffer.[/QUOTE]

I found a random cube online, with following values:


//const GLubyte Indices[] = {
//    6,1,1, 3,2,2, 2,3,3, 7,4,4,
//    8,5,5, 1,6,6, 4,7,7, 5,8,8,
//    7,9,9, 2,10,10, 1,11,11, 8,12,12,
//    5,13,13, 4,14,14, 3,15,15, 6,16,16,
//    8,17,17, 5,18,18, 6,19,19, 7,20,20,
//    1,21,21, 2,22,22, 3,23,23, 4,24,24
//};

//const GLubyte Indices[] = {
//    // Front
//    0, 1, 2,
//    2, 3, 0,
//    // Back
//    4, 6, 5,
//    4, 7, 6,
//    // Left
//    2, 7, 3,
//    7, 6, 2,
//    // Right
//    0, 4, 1,
//    4, 1, 5,
//    // Top
//    6, 2, 1, 
//    1, 6, 5,
//    // Bottom
//    0, 3, 7,
//    0, 7, 4    
//};

This compiles quite fine, i assume theres something wrong with the values i get from my model. But it does not make much sense since i can open it in different 3D programs as is.

[QUOTE=menzel;1237877]


const Vertex Vertices[] = {     {-0.307796,0.00433517,0},     {0.299126,0.00433517,0},     {0.299126,0.00433517,0.48337},     {-0.307796,0.00433517,0.48337},     {-0.307796,0.364153,0.48337},     {0.299126,0.364153,0.48337},     {0.299126,0.364153,0},     {-0.307796,0.364153,0} };  
const GLubyte Indices[] = {     7, 3, 2,      3, 7, 6,      5, 1, 4,      1, 5, 8,      7, 1, 8,      1, 7, 2,      3, 5, 4,      5, 3, 6,      5, 7, 8,      7, 5, 6,      3, 1, 2,      1, 3, 4  };


Your indices start at 1 and go to 8, you should index from 0 to 7 as your VBO only has 8 vertices in it.

Also, your glVertexAttribPointer calls seem wrong: stride is the size in bytes of one vertex, 3*sizeof(float) for the position, not sizeof(Vertex). I also don’t see color in your buffer.[/QUOTE]

Thanks for pointing that issue out. I just did “-1” in my parser and everything was fixed.

Okay, so i got the parsing stuff in place. Im trying to start from scratch with the code. Im trying to use VAO which is somewhat failing for me, since only 10% of the object is rendered. Im not sure why and how the rest is not rendered?

The parser stuff:


    struct ObjMeshVertex{
        Vector3f pos;
        Vector2f texcoord;
        Vector3f normal;
    };
    
    struct ObjMeshFace{
        ObjMeshVertex vertices[3];
    };

    struct ObjMesh{
        std::vector<ObjMeshFace> faces;
    };

    ObjMesh myMesh;

    for(size_t i = 0; i < faces.size(); ++i){
        ObjMeshFace face;
        for(size_t j = 0; j < 3; ++j){
            face.vertices[j].pos        = positions[faces[i].pos_index[j] - 1];
            face.vertices[j].texcoord   = texcoords[faces[i].tex_index[j] - 1];
            face.vertices[j].normal     = normals[faces[i].nor_index[j] - 1];
        }
        myMesh.faces.push_back(face);
    }

Setup:


        glGenVertexArraysOES(1, &_boxVAO);
        glBindVertexArrayOES(_boxVAO);

        int sizeOfFaces = myMesh.faces.size() * sizeof(ObjMeshFace);
        glGenBuffers(1, &_boxBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, _boxBuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeOfFaces, &(myMesh.faces[0]), GL_STATIC_DRAW);
        
      
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(ObjMeshVertex), 0);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(ObjMeshVertex), (void*)offsetof(ObjMeshVertex, texcoord));        
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE ,sizeof(ObjMeshVertex), (void*)offsetof(ObjMeshVertex, normal));
        
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glEnableVertexAttribArray(2);
        
        glBindVertexArrayOES(0);

Draw:


    glBindVertexArrayOES(_boxVAO);
    glDrawArrays(GL_TRIANGLES, 0, indicesize);  

Where indicesize = myMesh.faces.size()

glDrawArrays(GL_TRIANGLES, 0, indicesize);

Are you sure you have the right value for indicesize as this needs to represent all faces (where each face = 3 triangles, and each triangle=3 verticies).
So you could be a factor of 9 out.

[QUOTE=BionicBytes;1237994]

glDrawArrays(GL_TRIANGLES, 0, indicesize);

Are you sure you have the right value for indicesize as this needs to represent all faces (where each face = 3 triangles, and each triangle=3 verticies).
So you could be a factor of 9 out.[/QUOTE]

I have made some slight changes in my code and cut back to creating one array in the form of:
posX,posY,posZ,normX,normY,normZ

If we take an example i have 7055 faces (indices).
Each created in this form: f 716/4636/4636 717/4637/4637 710/4638/4638

Since i only need the position and norm i create an array of the size faces*6.

So if i were in the former case of using texturecoords i would be a factor 9 from the real size.

But so far i have following rendering, which is still “broken”.
[ATTACH=CONFIG]179[/ATTACH]

[QUOTE=Graphicz;1237996]If we take an example i have 7055 faces (indices).
Each created in this form: f 716/4636/4636 717/4637/4637 710/4638/4638
[/QUOTE]

7055 faces does not equal 7055 indices.

1 face = 3 verticies (to create a triangle) = 3 indicies.

f 716/4636/4636

This arrangement of “f x/y/z” implies that for each face your OBJ file contains vertex/normal/texturecoord.
Therefore your array sizes (assuming an interleaved array) would be #faces * (3 vertex + 3 Normal + 2 Texcoord) [glfloat]
and the number of indicies required would be #faces * 3