Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

998225 Posts in 39148 Topics- by 30559 Members - Latest Member: TinyAngryCrab

April 18, 2014, 07:40:10 AM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)OpenGL Interleaved VBOs, Strides and Offsets
Pages: [1] 2
Print
Author Topic: OpenGL Interleaved VBOs, Strides and Offsets  (Read 1495 times)
Sean A.
Level 8
***



View Profile Email
« on: March 18, 2013, 07:15:13 PM »

So I've been trying to wrap my head around VBOs and I can't seem to get it to work. I've been using LWJGL. I'm trying to draw a cube and I'm using an interleaved buffer with v3f,n3f,c4f,t2f setup. I am putting the arrays one after another into the buffer giving a VVCCNNTT result. Now when I set up the pointers from my understanding this is how the bytes should be arranged for each vertex (floats are 4 bytes):
Code:
             Amount    Bytes  Offset
Vertex  3f = 12bytes =  0-11  0
Normal  3f = 12bytes = 12-23  12
Color   4f = 16bytes = 24-39  24
Texture 2f = 8bytes  = 40-47  40

Stride = Total Bytes per Vertex = 12 * 4 = 48

So the code:
glVertexPointer( 3, GL_FLOAT, 48, 0);
glNormalPointer( GL_FLOAT, 48, 12);
glColorPointer( 4, GL_FLOAT, 48, 24);
glTexCoordPointer( 2, GL_FLOAT, 48, 40);

Should point to the correct places in the arrays

The results I get make it clear that it is looking in the wrong place. So I'm am hoping someone can point me in the right direction. If you need more context or code around this let me know.
Logged
ThemsAllTook
Moderator
Level 10
******


Alex Diener


View Profile WWW
« Reply #1 on: March 18, 2013, 09:18:32 PM »

Looks right to me. Maybe paste your VBO data initialization and glBufferData call? Also a screenshot, if it's drawn anything cool looking from plugging random memory into places it doesn't belong. Grin
Logged
Polly
Level 3
***


View Profile
« Reply #2 on: March 19, 2013, 07:08:59 AM »

I am putting the arrays one after another into the buffer giving a VVCCNNTT result.

This kind of sounds like your buffer first contains all vertex positions, then all vertex colors etc. A interleaved buffer should first contain all attributes / data of the first vertex, then the second vertex etc. But perhaps i simply misunderstood your statement Smiley
Logged
zalzane
Level 5
*****


View Profile
« Reply #3 on: March 19, 2013, 08:42:09 AM »

I don't use opengl so I'm not of much technical help here. However I can offer moral support! VBOs are a serious pain in the ass to implement in opengl for the first time, and to be quite frank it's probably one of the biggest hurdles for new devs. After you get it working for the first time, I suggest writing a wrapper class so that you never have to deal directly with the buffers again.

Also, if you've got data in the buffers and it isn't appearing correctly, you can inspect the contents of the buffers directly using gDEBugger.
Logged
Sean A.
Level 8
***



View Profile Email
« Reply #4 on: March 19, 2013, 07:22:01 PM »

Ok thanks for all the comments.

@Polly As far as I know you can interleave buffers in either way http://www.java-gaming.org/index.php?topic=24272.0 That tutorial describes both methods for interleaving.

So I should mention I'm indexing the VBO as well to reuse vertices, anyway here is some more code. This is basically the whole rendering, the only part missing is the arrays being created to store the data.
Code:
//Create Float Buffers
FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer(vertices.length+normals.length+colors.length+textures.length);
IntBuffer indexBuffer = BufferUtils.createIntBuffer(indices.length);

//Put the points
vertexBuffer.put(vertices);
vertexBuffer.put(normals);
vertexBuffer.put(colors);
vertexBuffer.put(textures);
vertexBuffer.flip();

indexBuffer.put(indices);
indexBuffer.flip();

IntBuffer ib = BufferUtils.createIntBuffer(2);

glGenBuffersARB(ib);
int vertexHandle = ib.get(0);
int indexHandle = ib.get(1);

glEnableClientState(GL11.GL_VERTEX_ARRAY);
glEnableClientState(GL11.GL_NORMAL_ARRAY);
glEnableClientState(GL11.GL_COLOR_ARRAY);
glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);

glBindBufferARB(GL_ARRAY_BUFFER_ARB,vertexHandle);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexBuffer, GL_STATIC_DRAW_ARB);
glVertexPointer(3,GL_FLOAT,12 * 4, 0);
glNormalPointer(GL_FLOAT,12 * 4, 3 * 4);
glColorPointer(4,GL_FLOAT,12 * 4, 6 * 4);
glTexCoordPointer(2,GL_FLOAT,12 * 4, 10 * 4);

glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,indexHandle);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexBuffer, GL_STATIC_DRAW_ARB);

glDrawArrays(GL_TRIANGLES,0,indices.length);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,0);

glDisableClientState(GL11.GL_VERTEX_ARRAY);
glDisableClientState(GL11.GL_NORMAL_ARRAY);
glDisableClientState(GL11.GL_COLOR_ARRAY);
glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);

ib.put(0, vertexHandle);
ib.put(1, indexHandle);
glDeleteBuffersARB(ib);

Here is an output image trying to draw one cube:


Right after I copied the text I realized glDrawArrays() is wrong and should be glDrawRangeElements() but I don't know how to use that.

Just a few addition VBO questions:

1. All of the tutorials I have read don't mention which parts of the rendering code can be executed once on object creation and what needs to be run every render loop

2. The LWJGL site mentions GL_DYNAMIC_DRAW_ARB and GL_STREAM_DRAW_ARB, I assume these have something to do with modifying the buffers once they are created but I'm not sure
Logged
ThemsAllTook
Moderator
Level 10
******


Alex Diener


View Profile WWW
« Reply #5 on: March 19, 2013, 09:08:15 PM »

@Polly As far as I know you can interleave buffers in either way http://www.java-gaming.org/index.php?topic=24272.0 That tutorial describes both methods for interleaving.

Ahh yeah, there's your problem. Both ways work, but they require different setup in the gl*Pointer calls. You have the data layout of the VVVCCC example (I believe this is called "planar"), but the gl*Pointer invocations of the VCVCVC example (non-planar).

If you want to stick with planar, you could change this:

Code:
glVertexPointer(3,GL_FLOAT,12 * 4, 0);
glNormalPointer(GL_FLOAT,12 * 4, 3 * 4);
glColorPointer(4,GL_FLOAT,12 * 4, 6 * 4);
glTexCoordPointer(2,GL_FLOAT,12 * 4, 10 * 4);

...to this:

Code:
glVertexPointer(3,GL_FLOAT, 0, 0);
glNormalPointer(GL_FLOAT, 0, vertices.length * 4);
glColorPointer(4,GL_FLOAT, 0, (vertices.length + normals.length) * 4);
glTexCoordPointer(2,GL_FLOAT, 0, (vertices.length + normals.length + colors.length) * 4);

Not 100% sure those offsets are correct, but you get the idea I hope! Passing 0 for stride makes GL assume your data is tightly packed, which is the case with the planar layout.

1. All of the tutorials I have read don't mention which parts of the rendering code can be executed once on object creation and what needs to be run every render loop

In (almost?) all cases, your GL state will stay exactly as you set it until you tell it to change. If you don't unbind or delete your buffers,  leave your client states enabled, and don't mess with gl*Pointer() elsewhere, your render loop can be as simple as the glDrawArrays()/glDrawElements()/glDrawRangeElements() call and nothing else. Basically anything that doesn't directly have to do with drawing to the screen or updating your visuals for animation can be left out of the render loop and only done once.

2. The LWJGL site mentions GL_DYNAMIC_DRAW_ARB and GL_STREAM_DRAW_ARB, I assume these have something to do with modifying the buffers once they are created but I'm not sure

Yep, those are hints you can give GL that may in some cases allow it to optimize your VBO for your particular usage of it. In simple terms, you want to use GL_STATIC_DRAW for data that will be drawn multiple times and never modified; GL_DYNAMIC_DRAW for data that will be drawn multiple times and modified at least once (using glBufferSubData()/glMapBuffer()/whatever); and GL_STREAM_DRAW for data that will be drawn only once.
Logged
Polly
Level 3
***


View Profile
« Reply #6 on: March 20, 2013, 03:32:52 AM »

As far as I know you can interleave buffers in either way http://www.java-gaming.org/index.php?topic=24272.0 That tutorial describes both methods for interleaving.

That tutorial uses the incorrect term for what is actually a regular batched buffer. Check out the "Formatting VBO Data" section on the OpenGL wiki.
Logged
Sean A.
Level 8
***



View Profile Email
« Reply #7 on: March 20, 2013, 05:38:45 AM »

Ohhhhh ok thanks, is there any performance advantage for VVVCCC or VCVCVC? But yeah the tutorials put everything I posted in the render loop which is weird to me, so I can safely move all of the buffer putting and binding and glEnableClientState calls into an init() function, and then call glDrawRangeElements in the render loop and then delete the delete the buffer in a destroy() function?
Logged
Polly
Level 3
***


View Profile
« Reply #8 on: March 20, 2013, 05:49:01 AM »

Ohhhhh ok thanks, is there any performance advantage for VVVCCC or VCVCVC?

A interleaved buffer will ( generally ) cause fewer cache misses. However, alignment is a big factor as well ( obviously .. since of how the memory addresses are calculated ), so depending on your exact vertex attribute formatting it might not always be the preferred approach. And when you want to update various attributes / ranges dynamically, it complicates the choice even further Smiley
Logged
powly
Level 3
***



View Profile WWW
« Reply #9 on: March 20, 2013, 06:54:10 AM »

Not going to say this is how it works, but it would make sense if the driver rearranged the data to be in the most efficient format for that GPU no matter how you input it.
Logged
zalzane
Level 5
*****


View Profile
« Reply #10 on: March 20, 2013, 08:18:08 AM »

Not going to say this is how it works, but it would make sense if the driver rearranged the data to be in the most efficient format for that GPU no matter how you input it.

If you gave the driver information that was not in the format that it planned on using, it would have to waste god knows how much overhead rearranging your data to match the technique it uses.
Logged
powly
Level 3
***



View Profile WWW
« Reply #11 on: March 20, 2013, 08:48:18 AM »

Doing AAABBBCCC<->ABCABCABC doesn't produce 'god knows how much overhead'. It's a pretty small thing and probably well worth it if it makes the cache usage while rendering more efficient. Could be done as a relatively simple circuit in the harware, too - the thing is pretty much out[i*dimensions+dimension_i] = in[i+dimension_i_start] for all vertices i and dimensions (position, color, normal, ...) dimension_i. And once again, I will stop with the offtopic after this one.
Logged
ham and brie
Level 3
***



View Profile Email
« Reply #12 on: March 20, 2013, 10:11:43 AM »

It would be risky for an OpenGL implementation to second-guess the programmer, who may well have laid out the contents of the buffer knowing that they will later overwrite part of the data and want it in a contiguous block.

It would be difficult to do the rearrangement too. For one thing, setting the data in a buffer is separate from the calls which control how the data in a buffer is to be used, which can come only just before a draw call and can be different for multiple uses of the same buffer.
Logged
powly
Level 3
***



View Profile WWW
« Reply #13 on: March 20, 2013, 12:41:41 PM »

...  and can be different for multiple uses of the same buffer.

True, doesn't make sense. The API would also probably force either way if it mattered.
Logged
Sean A.
Level 8
***



View Profile Email
« Reply #14 on: March 20, 2013, 06:18:24 PM »

Awesome all I had to do was fix those pointer values and now it is working well. Two more questions though:

1. Lets say I wanted to do a textured cube with the same texture on every side. I can't use indexed VBOs can I because if I reuse vertices the texture coordinates won't work right?

2. glDrawRangeElements, I understand all of the arguments except for the 'end' and 'count' arguments (the 3rd and 4th ones), I know they have to do with the amount of things being drawn but is it the amount of triangles or vertices or what?
Logged
Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic