What is the "correct" way to implement VBO texturing?

Started by
5 comments, last by Qrikko 12 years, 3 months ago

Hi,

First of all I am feeling like this is a question I should have been able to find the answer to either here on the forums or elsewhere by now. However I don't know if I'm just slow in my brain, bad at searching or what's going on, so anyone which have seen this question tons of times before: So sorry to ask it again.

So here's the deal. I am implementing some rendering code, nothing fancy really I'm not all that good at rendering but have some experience gained on what I guess would be called hobby-level. What I am doing right now is trying to find out the best practices around VBO (Vertex Buffer Objects) and if that even still is a good way to go for rendering.

The background is that I am writing a small script for blender to fetch the data I need (why not use an already written exporter? Well there are a couple of reasons, a few being: I want to do it because I find it fun, it helps me understand a bit better how blender work with the data, I can get exactly the data I need and nothing else organized in a way I find easy to parse...)

I am then trying to take this data and run in an openGL application.

So far all is kind of good, but I am thinking that I'm missing something, or rather I know that there are something I don't fully understand.

the way I represent data would be something like this (I am not sure about the exact implementation and this will serve only as an example)


typedef struct {
float position[3];
float uv[2];
} vertex;
GLushort *indices;


EXAMPLE:

Take a cube for example:

cube.png

If I unwrap this cube (I could do it in many ways but I've chosen to try to keep it simple)



unwrap.png

From the unwrap (I hope I got it right, but it should at least be useful to prove my point), we see that different UV-coordinates are assigned for the same vertex in different faces. This is nothing strange and I do understand why it's like this but I wanted to keep this in here for reference.

The code-example would mean that each vertex has one uv-coordinate which would make perfect sense to me if I were using a flat model with any shared vertex also sharing the texture coordinate.

So there is a contradiction in this, i.e. when I use VBO every index point at one vertex, and one vertex has one position (coordinate) and one texture coordinate, while the unwrap show that this really is rarely the case, there are vertices (v1, v2, v3 and v4 to be specific) which in fact do share the same uv-coordinate so my top face is good and will render my texture correct. And depending on how I choose the uv-coordinates for the other faces I can get one (or maybe a couple of them, not all that interesting) correct as well, but for the other faces (i.e. v5, v6, v7, v8) the uv-coordinate is different depending on which face is using them.

So finally on to the question:
What is the best practice here, as I see it there are a couple of options (might well be options I didn't even think of)?
1) write one vertex per vertex in every face, or duplicate vertices. However this would mean a great overhead since many of those duplicated vertices actually do share texture coordinates as well.
2) take it a bit further and duplicate only the vertices which doesn't share uv-coordinate. This feel like it might be it? I mean if there aren't a way to let the indexing look it up in some other way which tend to become quite messy and complicated really quick when I think about it.
3) some other way, like separating out the uv-buffer from the vertices, and run a second index pointer on them. This feel a bit messy and if I am doing this there are other rendering techniques which could do the job in a simpler way with about the same performance (I believe but it's just a guess).

So again what is the best practice, is it common to duplicate the vertices which doesn't share the UV-data?

Thanks for taking the time to read this.

"Who ever put in this magic number should die, in the face" - found documented in the code of TGE
Advertisement
If two vertices have different texture coordinates, then the two vertices are not the same. Your unwrapped cube example thus has 14 vertices, not 8. Not only is it best practice or common to duplicate vertices with different attribute, but you are required to do so. The vertices simply aren't the same, and you cannot expect two different vertices to share the same slot in a vertex array.

As an example, if you also throw in normals into your vertex attributes, you will notices that you cannot share any of the vertices anymore, and you end up with 24 vertices for the cube. Even though many of them share position, none of them share the other attributes.
Thanks that clears it up a bit, I think that my problem is the view of the index.. But well that clear up a bit and help me in thinking about it so big step forward there!

Then the follow up question emerge..

What is the gain from using VBO over other techniques? I read that it is stored internally and may be faster for that reason, but as I thought about it it was kind of neat to share some of the data (as opposed to arrays I guess was my idea).

Then again... I might be a bit stupid once more, since when I think about it, it's really only a few vertex positions being "duplicated" in a bigger uv-map right? I mean if I were to unwrap a model of a can with 1000 vertices, I would only have the open end in the uv-map making duplicates.. meaning that I could potentially actually still re-use quite a bit.
"Who ever put in this magic number should die, in the face" - found documented in the code of TGE
Indices are good for sharing vertices. Your problem here though is that there is no data to be shared. The cube is simply the worst case you can ever come up with to demonstrate the benefit of shared vertices. Typically you can reduce the total storage by at least half when you have smooth models where you have continuous edges instead of discontinuous edges like in this case.

But your question is somewhat ill-posed, perhaps because of some wrong terminology or because I'm reading it wrong. The benefit of VBO is that it stores your vertex arrays in driver-managed memory. This allows the driver to store it in high-performance memory on the graphic card for example. Not to mention that this is the only say to store vertex arrays in OpenGL 3.0 and later with the forward compatible profile, the old vertex array mechanism only allowed you to store the arrays in system memory which may not be the optimal place.

But the problem you have here with shared indices has nothing to do with VBO. It is true for any vertex array, whether stored in a VBO or in system memory. The only way to get away with it is to use immediate mode, which is low performing in comparison to vertex arrays, and even deprecated if you care about OpenGL 3.0 and later.
Cool, that shed some light on the differences really cool to take the time to help me wrap my head around some of the things and clear some misunderstandings I've been having.



Indices are good for sharing vertices. Your problem here though is that there is no data to be shared. The cube is simply the worst case you can ever come up with to demonstrate the benefit of shared vertices. Typically you can reduce the total storage by at least half when you have smooth models where you have continuous edges instead of discontinuous edges like in this case.


Aye I kind of realized that as I posted the answer, since a cube kind of unwraps in almost every vertex of course that will create a pretty nasty case to study.


But your question is somewhat ill-posed, perhaps because of some wrong terminology or because I'm reading it wrong. The benefit of VBO is that it stores your vertex arrays in driver-managed memory. This allows the driver to store it in high-performance memory on the graphic card for example. Not to mention that this is the only say to store vertex arrays in OpenGL 3.0 and later with the forward compatible profile, the old vertex array mechanism only allowed you to store the arrays in system memory which may not be the optimal place.

But the problem you have here with shared indices has nothing to do with VBO. It is true for any vertex array, whether stored in a VBO or in system memory. The only way to get away with it is to use immediate mode, which is low performing in comparison to vertex arrays, and even deprecated if you care about OpenGL 3.0 and later.


Sorry about any bad used terminology, I understand that the problem is not just for VBO, the problem I had rather were to understand the way to use vertex buffer objects I guess.. That is (as I suspected) due to lack of knowledge about what the best-practice (which turned out to not only be best-practice but necessary) when arranging the data.

I do however feel enlightened and pretty secure that this conversation have given me enough understanding and more importantly the difference in a vertex position and data (since I kind of started out with the view that the position kind of was the vertex, and the other.. well I don't even know since your example with the number of vertices in the cube and the unwrap of it relate helped me understand that a vertex with position p1 and uv-coord uv1 is not the same vertex as one with p1, uv2.. Same position but not same vertex entry).

Cheers, and thank you for the help!

(now if I only can understand how to mark the topic as solved...)
"Who ever put in this magic number should die, in the face" - found documented in the code of TGE

I do however feel enlightened and pretty secure that this conversation have given me enough understanding and more importantly the difference in a vertex position and data (since I kind of started out with the view that the position kind of was the vertex, and the other.. well I don't even know since your example with the number of vertices in the cube and the unwrap of it relate helped me understand that a vertex with position p1 and uv-coord uv1 is not the same vertex as one with p1, uv2.. Same position but not same vertex entry).

It is not unreasonable to think of a vertex as a point in space that you use to connect to form surfaces. But in my opinion, the terminology and the double meaning of the term vertex (a point vs. an entity with unique attributes; OpenGL uses the latter) is confusing. With shaders and such today, it is not unreasonable that a vertex even excludes a position attribute; it can contain generic parameters (for example polar coordinates) that a vertex shader uses to generate the position attribute.


(now if I only can understand how to mark the topic as solved...)

It is usually advised not to mark it as such. Your thank you-post is enough to ackowledge the thread, and the discussion can continue in case someone does not agree with me smile.png
Ok, cool.

I haven't been doing much game/render related work for quite some time, sad but it's how the story goes, had to work with other things and kind of got away from OpenGL and so on. (for reference my degree is in game programming and I used to work with it but later years I've not been as active). So it's a lot to wrap my head around but it's fun to try to get started a bit again with it all.

This conversation actually helped me a lot, and I know now how to adjust my exporter to actually get the data I want rather then a almost working textured mesh :P

I've still got some ways to go to get my head around the way to think shaders in a more natural way it was kind of the new thing really coming strong when I last really worked with rendering and back then it was magic to me and I left it at that. But my goal is that I will get deeper knowledge there as well I'm just starting out and want to kind of put the proper foundation of knowledge so to speak. (hence the question about how to understand VBO (which I see now is what I really needed to ask from the start.. good enough for me you answered that even if the question was well hidden) )
"Who ever put in this magic number should die, in the face" - found documented in the code of TGE

This topic is closed to new replies.

Advertisement