PDA

View Full Version : Drawing a Wavefront OBJ cube



Graphicz
05-22-2012, 01:42 PM
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(CACurren tMediaTime()), 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:

738

menzel
05-23-2012, 03:10 AM
Your indices start at 1, you should count starting from 0.

Graphicz
05-23-2012, 06:48 AM
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'.

menzel
05-23-2012, 07:27 AM
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.

Graphicz
05-23-2012, 07:31 AM
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..

Graphicz
05-23-2012, 07:33 AM
http://en.wikipedia.org/wiki/Wavefront_OBJ


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 ...

Graphicz
05-23-2012, 08:33 AM
I tested following which was found randomly:





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.

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.

Graphicz
05-23-2012, 09:01 AM
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.

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

Graphicz
05-24-2012, 12:39 PM
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()

BionicBytes
05-25-2012, 05:31 AM
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.

Graphicz
05-25-2012, 05:38 AM
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.

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".
741

BionicBytes
05-25-2012, 08:21 AM
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


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