Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (576)
games submitted by our members
Games in WIP (498)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  LWJGL Tutorial Series - Vertex Buffer Objects  (Read 2946 times)
0 Members and 1 Guest are viewing this topic.
Offline SHC
« Posted 2013-09-09 11:00:04 »

LWJGL Tutorial Series - Vertex Buffer Objects


Welcome to the seventh part of this series 'Vertex Buffer Objects'. If you didn't read my previous tutorials in this series, I recommend you to read them first to get an understanding. This tutorial assumes that you clearly understood the previous one 'Vertex Arrays' since it follows from that. If there are any mistakes or corrections, please notify them with comments. Now that we are ready to learn VBOs, let's first see what they actually are.

Vertex Buffer Objects


Vertex Buffer Object (VBO for short) is an OpenGL feature that enables us to directly send the buffers of vertex information including color information or the texture information directly to the graphics card for high performance. This feature is introduced in OpenGL 1.5 in 2003 and nowadays most graphic cards support upto OpenGL 3.0. So, we needs to import the static methods of OpenGL 1.5. In LWJGL, the methods are present in classes with the OpenGL version name. We can import all the 1.5 methods using

1  
import static org.lwjgl.opengl.GL15.*;

This enables us to use the methods which are introduced in OpenGl 1.5. Don't remove the previous import, we still need it for previous OpenGL methods. In this tutorial, we're going to draw a texture all over the display with VBO. This involves creating an ID for the vertex buffer and an ID for the texture buffer and uploading the vertex data directly to the graphics card and render them. So let's create them in the init method.

Creating a Vertex Buffer Object


Let's start with code in our init method. I'll show the code first and then I'll explain it line by line.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
int vboVertexID;
int vboTextureID;

public void init()
{
    // Setup OpenGL and load texture

    // Create the buffers
   FloatBuffer vertices = BufferUtils.createFloatBuffer(2 * 4);
    vertices.put(new float[]
    {
        0,   0,
        800, 0,
        800, 600,
        0,   600
    });
    vertices.rewind();

    FloatBuffer texCoords = BufferUtils.createFloatBuffer(2 * 4);
    texCoords.put(new float[]
    {
        0, 0,
        1, 0,
        1, 1,
        0, 1
    });
    texCoords.rewind();

This is just like how we made for vertex arrays, so I' not going through that code again. The only change is that I've modified the vertices so that now the quad occupies the whole display. Now, let's generate the vbo.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
// Create the vbo
vboVertexID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

vboTextureID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboTextureID);
glBufferData(GL_ARRAY_BUFFER, texCoords, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

Now I'm going to explain the syntax of each of those functions. You can understand what
glGenBuffers()
does so I'm skipping it. Next function is
glBindBuffer()
which is also understandable. It just binds the vertex id we generated before as an array buffer. Now we came to
glBufferData()
function for which I'm giving it's syntax here. If you need full reference, check out it's reference page.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
/**
 * Creates and initializes a buffer object's data store.
 *
 * @param target Specifies the target buffer object. The symbolic
 *               constant must be GL_ARRAY_BUFFER,
 *               GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER,
 *               or GL_PIXEL_UNPACK_BUFFER.

 * @param data Specifies a FloatBuffer that will be copied into
 *             the data store for initialization.

 * @param usage Specifies the expected usage pattern of the data
 *              store. The symbolic constant must be GL_STREAM_DRAW,
 *              GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW,
 *              GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW,
 *              GL_DYNAMIC_READ, or GL_DYNAMIC_COPY.
 */

void glBufferData(int target, FloatBuffer data, int usage);

The target is
GL_ARRAY_BUFFER
since our buffers are filled with arrays of data. The next parameter we pass is our vertices buffer, i.e.,
vertices
and for the last parameter, we specify
GL_STATIC_DRAW
which means the buffers are only filled once at construction but can be used a lot of times. And in the end, we're doing
glBindBuffer(GL_ARRAY_BUFFER, 0)
which means we are unbinding the vbo. The same way, we construct the texture buffer. And now, it's time for rendering.

Rendering a VBO


Now, we are in the render method and I'm showing the code for rendering a vbo. It needs us to first bind the vertex buffer id and set the vertex pointer to it. Then we bind the texture coord buffer and set the pointer. Now we enable vertex arrays and texture coord arrays, render using the
glDrawArrays()
function and finally disable the client states. Let's get into the code.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
// Bind the vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, vboVertexID);
glVertexPointer(2, GL_FLOAT, 0, 0);

// Bind the texture buffer
glBindBuffer(GL_ARRAY_BUFFER, vboTextureID);
glTexCoordPointer(2, GL_FLOAT, 0, 0);

// Enable Client states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

// Draw the textured rectangle
glDrawArrays(GL_QUADS, 0, 4);

// Disable Client states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

The pointer functions are slightly different than the ones we used in the previous tutorial. The change is that we are now using the buffers already sent to the graphic card. Anyway, if you want the syntax of the
glVertexPointer()
function is located here. Don't run it just now, we have one final stage that is disposing the buffers at the end.

Disposing VBO


You must dispose the VBO before you exit your application. This is because, we've sent it to the graphic card it is our responsibility to clear the memory on the graphics card when exiting. Or else, there may be no space left if yours is a large project for the user to use another program after yours closes. For this purpose, we are going to use the dispose method we made in our game class. You can simply delete the buffers with
glDeleteBuffers()
function.

1  
2  
3  
4  
5  
6  
public void dispose()
{
    // Dispose the buffers
   glDeleteBuffers(vboVertexID);
    glDeleteBuffers(vboTextureID);
}

That removes unnecessary buffers from the GPU. Now it's time to run it. When you run it, you will see something like this.



Hurray! We've successfully used VBOs to render a textured quad on the screen. That's the end of this tutorial and if you found any mistakes or corrections, please notify them to me with comments and I will correct them. In the next tutorial, let's make a 'Pong' game with all the concepts we've learnt till now.

Source Code


Tutorial7.java

Offline RobinB

JGO Knight


Medals: 37
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #1 - Posted 2013-09-09 12:46:04 »

Nice tutorial again, however dont forget about:
1  
glDrawElements(GL_TRIANGLES, indexsize, GL_UNSIGNED_INT, 0);

This call allows shared vertices (faster then normal vbo's).

Someone here wrote a bigger tutorial about vbo's, where a lot more is discussed, you should take a look there.
Offline SHC
« Reply #2 - Posted 2013-09-09 13:14:37 »

@RobinB

Are you referring to Riven's article? There's no explanation in it.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Online theagentd
« Reply #3 - Posted 2013-09-09 15:30:11 »

glDrawElements() isn't needed in this case since he's using GL_QUADS, which in practice is handled very similarly to two triangles forming a quad using 4 vertices, so the vertices are already reused. GL_QUADS is however deprecated in OpenGL 3+, in which case you can either use an index buffer to construct two triangles using those four vertices, or you could simply change GL_QUADS to GL_TRIANGLE_FAN which in this case (a single quad) would work the same as GL_QUADS.

Myomyomyo.
Offline quew8

JGO Coder


Medals: 23



« Reply #4 - Posted 2013-09-09 18:06:52 »

glDrawElements() is something you use if you are also using an index array (as in index array or IBO). Personally I think you should at least mentioned this. Maybe you will in another tutorial? Another thing to mention would be interleaving data - you will see large performance increases.

Also glVertexPointer() / glTexCoordPointer() / glVertexAttribPointer() are 99% of the time where people make mistakes with VBOs and I don't think its enough to point them to the documentation. It will be enough for some, but not for most. 
Offline davedes
« Reply #5 - Posted 2013-09-09 19:56:29 »

Also note.. if you plan to make any tutorials in the future about the programmable pipeline (i.e. what constitutes OpenGL in the 21st century), you will need to change all of these tutorials since they rely on so many deprecated functions (glEnableClientState, GL_QUADS, etc). Smiley

IMHO it would be more useful to guide new users in the direction of the programmable pipeline, rather than going into depth on deprecated functionality. It only leads to confusion later, when they begin to write GL3+ code and have all this prior knowledge of deprecated functions.

This is why you tend to see a lot of GL3+ apps that have deprecated code lingering around, like
glEnable(GL_TEXTURE_2D)
.

Offline quew8

JGO Coder


Medals: 23



« Reply #6 - Posted 2013-09-09 20:26:16 »

With the previous tutorial on vertex arrays, I agree. However VBOs are very much modern OpenGL, it's only their use that changes in programmable pipeline. So most of the functions are in fact incredibly similar ie
glEnableClientState -> glEnableVertexAttrib
glVertexPointer -> glVertexAttribPointer with only one extra argument.
As it happens, I think those are the only function calls you must change. I might have missed some though.
Online HeroesGraveDev

JGO Kernel


Medals: 212
Projects: 11
Exp: 2 years


If it wasn't Awesome, it wasn't me.


« Reply #7 - Posted 2013-09-09 21:58:45 »

What about mapped buffers?

Offline SHC
« Reply #8 - Posted 2013-09-10 05:00:45 »

I'm thinking of touching this topic after the introduction of 3D. I'll mention interleaved vbos and mapped buffers there.

@davades

I don't think they confuse really too much and I started with immediate mode since it is easy to understand. I'm still in OpenGL 1.5 and I'll start with modern OpenGL with the introduction to shaders.

Offline quew8

JGO Coder


Medals: 23



« Reply #9 - Posted 2013-09-10 17:55:43 »

So you're adopting the one lesson ahead of the pupils approach.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #10 - Posted 2014-04-15 21:42:17 »

Unlocked upon request Pointing

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Pages: [1]
  ignore  |  Print  
 
 

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (15 views)
2014-04-15 18:08:23

BurntPizza (13 views)
2014-04-15 03:46:01

UprightPath (27 views)
2014-04-14 17:39:50

UprightPath (12 views)
2014-04-14 17:35:47

Porlus (29 views)
2014-04-14 15:48:38

tom_mai78101 (51 views)
2014-04-10 04:04:31

BurntPizza (110 views)
2014-04-08 23:06:04

tom_mai78101 (211 views)
2014-04-05 13:34:39

trollwarrior1 (179 views)
2014-04-04 12:06:45

CJLetsGame (185 views)
2014-04-01 02:16:10
List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:05:20
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!