PDA

View Full Version : VBO and triangle structure problem



nullPointer
01-31-2013, 03:38 PM
Hi,
I'm just trying with VBO and I've already did some basics with drawing points but now I want to draw triangles and I'm in a corner. Here's the problem. In most tutorials I see that vertex is defined something like this:


struct vertex
{
vec3 pos;
vec3 normal;
vec2 uv;
//plus more (?)
};

struct triangle
{
unsigned int indices[3];
};

Then you have triangles with indices to these vertices and all is well. Eg.

mesh class:


vertex * vertices;
triangle * triangles;
//or STL vectors of these

But in my engine I have data layout like this:


vertex
{
vec3 position
}

triangle
{
unsigned int vertexIndices[3];
unsigned int normalIndices[3];
unsigned int uvIndices[3];
}

The problem is when I create IBO it doesn't provide stride (if I'm correct) and in general I think it won't work with my data layout. You may ask - why did I wrote it this way? Well at first it seemed more "natural" to treat vertex only as a point in 3d space. Also it made more sense when I was writing OBJ loader, where data for a triangle/face is stored like this f 1/1/1 2/2/2 3/3/3 (so basically collect all vertices, then normals, then uvs, then triangles with indices to these guys). In addtition it worked well with immediate mode (I know, right...) and display lists (they are alright, but I'm writing vertex skinning so VBO look more "applicable" and also I want to do it the right way). The question is - can I somehow get away with this design and force OGL to use this data layout or I have to redesign it from the very bottom?

thokra
02-01-2013, 02:17 AM
The OBJ format doesn't define indices in a way OpenGL (and Direct3D) can understand. It's because indices in your example refer to three disjunctive arrays of data - vertices, tex coords and normals. OpenGL can only deal with a single index array at a time which stores uniquely to a set of vertex attributes.

So, what you need to do is to check every single vertex attribute in the OBJ file (i.e. v/t/n) and if you find a triplet containing even a single index that's duplicate you need to create a new set of attributes and a new unique index. The ultimate goal is to have an index array where each index refers to a unique set of single of vertex attributes.

For instance, consider two triangles who's vertices share a single normal. In an OBJ file, indices might look like this:

f 1//1 2//1 3//1 # first tri
f 1//1 3//1 4//1 # second tri

Translating this directly to a packed OpenGL vertex buffer would look like this (indices below):

---------------------------------------- positions ------------------------------------ ------------------------------------- normals -------------------------------------
[v1_x, v1_y, v1_z, v2_x, v2_y, v2_z, v3_x, v3_y, v3_z, v4_x, v4_y, v4_z || n1_x, n1_y, n1_z, ???????????????????????????????????????]
--------- 1 -------- --------- 2 -------- --------- 3 -------- --------- 4 -------- --------- 1 -------- --------- 2 -------- --------- 3 --------- -------- 4 --------

Now, you can see, that there are multiple unique positions (at 1,2,3 and 4) but only a single normal (1). Since you can maintain two seperate arrays for positions and normals when loading the OBJ file that's ok. OpenGL, however will try to find positions with indices 1,2,3 and 4 and find normals with the exact same indices. However, there is no normal at 2, 3 and 4 unless you duplicate the normal at index 1 three times. If the OBJ file maintained data as needed by OpenGL the faces would be described like so:

f 1//1 2//2 3//3 # first tri
f 1//1 3//3 4//4 # second tri

You can see, the index for positions and normals is the same unique index.

EDIT: As an excercise, model a simple cube with unique face normals for each side. Then look at the OBJ file and try to work out how the corresponding vertex and index buffers would have to look like for display with OpenGL.

nullPointer
02-01-2013, 09:32 AM
Thank you for detailed answer however I already knew the basics - the cube example is bit too much :). I just wanted to get the confirmation if that's possible with my current layout, but that's alright - it's better to get more info than needed than less :). I guess I have to pack some rations and dive into the code for several days, eugh... Kinda sucks that I have to copy some of the data in order to get the proper layout. I'm always going for space savings so this doesn't feel right in my guts xD. But then again there's the space<->performance tradeoff. With display lists it didn't really matter cause I could compile (draw) mesh in any way I like, just like with immediate mode. I could stick with display lists but I want to add vertex skinning and I don't see any solution for this, hence the VBOs.

Maybe this is bit offtopic but I'd ask it anyway - what would you recommend for data layout in vertex structure that is passed for vertex skinning?


vetrex
{
vec3 pos;
vec3 normal;
vec2 uv;
matrix4x4 TBN; //for bump mapping
unsigned int weightCount;
unsigned int startIndex;
}

Is pos (position) actually needed with vertex skinning? Because it doesn't really matter since I construct the position in my vertex shader from bones and weights - it might as well be (0,0,0)? But then again, if I cut out the position there's nothing to draw :D. Does it make sense to store extra zero vectors just for compatibility reasons? I know it sounds kinda like drawing vertices without actually providing any vertices. I may have missing something so I thought I'd better ask more experienced OGL users.