Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (489)
Games in Android Showcase (112)
games submitted by our members
Games in WIP (553)
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  
  The need of VAOs and minor confusion  (Read 990 times)
0 Members and 1 Guest are viewing this topic.
Offline noodleBowl

Senior Newbie





« Posted 2014-01-11 17:07:56 »

I was going over my render method and I started thinking. Do I need a VAO? All the tutorials I have looked at go over VAOs, but do I need them if my data is dynamic (changing every frame)?

I understand that VAO is a state object that is s supposed to hold the 'state' of Vertex Array Pointers for the VBOs I bind and etc. That if I bind a VAO and then use glEnableAttribPointer, bind a VBO, and glVertexAttribPointer to pointer to the VBO data a record is saved into the VAO. Where I can call the VAO bind function in my render method and everything will know how to draw.

But my confusion kind of comes in when the data I'm using is dynamic and changing every frame. If I have my render method as:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
   public void render()
   {
      //Use the shader program
     glUseProgram(shaderProgramHandle);
     
      //Get the Uniform for the MVP shader
     glUniformMatrix4(matrixBufferHandle, false, mvpBuffer);
     
      //Enable the VAO and its attributes
     glBindVertexArray(vertexArrayHandle); //Can comment out and has no effect; Never bound until this point
     glEnableVertexAttribArray(0);
     
      //Bind the Vertex Buffer and indicate where the Vertex are
     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle);
      glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
     
      //glDrawArrays(GL_TRIANGLES, 0, 3);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
      GL11.glDrawElements(GL_TRIANGLES, indexDrawCount, GL11.GL_UNSIGNED_INT, 0);
     
      glDisableVertexAttribArray(0);
   
   }


Do I really need the VAO? Would my app be faster with out them or with them? Or am I doing a bad 'thing' rebinding all the Vertex Attributes and etc every single time my render method is called? Should I only be rebinding the VAO, does this change (The rebinding) if my data is dynamic?
Offline theagentd
« Reply #1 - Posted 2014-01-11 17:41:05 »

In OGL3+ you can't render anything without a VAO. Like you said, VAOs only hold state, specifically which buffers should be read and how they should be interpreted, so regardless of what you're drawing you need one.

You seem to have missed something though. There's no need to set up your VAOs each time you render. You should bind them and set them up once. Then when you want to render with them you simply bind them and render.

Myomyomyo.
Offline noodleBowl

Senior Newbie





« Reply #2 - Posted 2014-01-11 18:07:09 »

I see so I really should be doing this

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  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
   private void initializeVAO()
   {

                //Create and generate the VAO
     IntBuffer vertexArrayBuffer = BufferUtils.createIntBuffer(1);
      glGenVertexArrays(vertexArrayBuffer);      
      vertexArrayHandle = vertexArrayBuffer.get(0);

                //Create and generatate the Vertex Buffer and  Index BUffer
     IntBuffer buffers = BufferUtils.createIntBuffer(2);
      glGenBuffers(buffers);
      vertexBufferHandle = buffers.get(0);
      indexBufferHandle = buffers.get(1);

      //Bind the VAO and set up the Vertex Attributes
     glBindVertexArray(vertexArrayHandle);
      glEnableVertexAttribArray(0);
     
      //Bind the Vertex Buffer and indicate where the Vertex are
     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle);
      glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
     
      glBindVertexArray(0);
   }

   public void Render()
   {
      //Use the shader program
     glUseProgram(shaderProgramHandle);
     
      //Get the Uniform for the MVP shader
     glUniformMatrix4(matrixBufferHandle, false, mvpBuffer);
     
      //Enable the VAO and its attributes
     glBindVertexArray(vertexArrayHandle);
     
      //glDrawArrays(GL_TRIANGLES, 0, 3);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
      GL11.glDrawElements(GL_TRIANGLES, indexDrawCount, GL11.GL_UNSIGNED_INT, 0);
     
      glBindVertexArray(0);
   }


The index buffer call is that correct? In the sense that it is separate from the VAO

Also if I'm loading in data every frame or so through a batching system, I assume I would need to switch between multiple VAOs every Nth frame correct?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline theagentd
« Reply #3 - Posted 2014-01-11 18:17:42 »

Much better! The index buffer binding is also stored in the VAO though, so you can just bind it when initializing once. You're right that it's a bit weird though.

Tip: There are LWJGL-specific overloaded versions of glGenVertexArrays(), glGenBuffers() and all other glGen***() functions that allocate a single VAO, VBO or whatever.

For example,
1  
2  
3  
IntBuffer vertexArrayBuffer = BufferUtils.createIntBuffer(1);
glGenVertexArrays(vertexArrayBuffer);      
vertexArrayHandle = vertexArrayBuffer.get(0);

does the same thing as
1  
vertexArrayHandle = glGenVertexArrays();


The same thing works for framebuffers, textures, buffers, etc.

Myomyomyo.
Offline noodleBowl

Senior Newbie





« Reply #4 - Posted 2014-01-11 19:59:23 »

Ok I think I got it

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
   private void initializeVAO()
   {
      //Bind the VAO
     glBindVertexArray(vertexArrayHandle);
      glEnableVertexAttribArray(0);
     
      //Bind the Vertex Buffer and indicate where the Vertex are
     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle);
      glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
     
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
     
      glBindVertexArray(0);
   }


Is there a way to force a certain min openGL context? Can I force my app to only allow a openGL 3.0 or better context?
Offline theagentd
« Reply #5 - Posted 2014-01-11 23:30:54 »

1  
Display.create(new PixelFormat(24, 0, 0, 0, 0), new ContextAttribs(3, 2)); //For version 3.2

With this code you'll get an exception if the requested context can not be created, but some drivers can be a bit tricky. For example, some Mac versions do not support OGL 3.2 with compatibility mode. You need to explicitly tell it to use the core profile without compatibility:

1  
Display.create(new PixelFormat(24, 0, 0, 0, 0), new ContextAttribs(3, 2).withProfileCompatibility(false).withProfileCore(true));


This will also remove all deprecated functionality (= disable compatility mode), so if your game is relying on such functions it'll not work as expected. It's also a good idea to check if the requested context is correct by checking the OpenGL version using
GLContext.getCapabilities().OpenGL32
.

Myomyomyo.
Offline noodleBowl

Senior Newbie





« Reply #6 - Posted 2014-01-13 03:20:39 »

Ok cool! Kinda of sucky about the tricky drivers though

Can we go back to the VAOs, while I under stand I should just be binding my VAO. What if my data is not static or I need to swap between buffers I fill on the fly?

I read that I need to use multiple VAOs if I wanted to implement a multiple VBO system; I assume this applies to a double buffer or Mapping system
So for example lets say we have / want a double buffer system. So we make our VAOs like so
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
   private void initializeVAO()
   {
      //Bind the first VAO and vertexBuffer handle
     glBindVertexArray(vertexArrayHandle[0]);
      glEnableVertexAttribArray(0);
      glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle[0]);  //Handle to second vertex buffer; Data in there is dynamic and changes each frame
     glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle); //No need for 2 index buffer handles; Contain the same data and is static
     glBindVertexArray(0);

      //Bind the second VAO and vertexBuffer handle
     glBindVertexArray(vertexArrayHandle[1]);
      glEnableVertexAttribArray(0);
      glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle[1]); //Handle to second vertex buffer; Data in there is dynamic and changes each frame
     glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle); //No need for 2 index buffer handles; Contain the same data and is static
     glBindVertexArray(0);
   }


Where our render method looks like
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
   public void endRender()
   {
      //Use the shader program
     glUseProgram(shaderProgramHandle);
     
      //Get the Uniform for the MVP shader
     glUniformMatrix4(matrixBufferHandle, false, mvpBuffer);
     
      //Enable the VAO and its attributes
     glBindVertexArray(vertexArrayHandle[useBuffer]);
     
      GL11.glDrawElements(GL_TRIANGLES, indexDrawCount, GL11.GL_UNSIGNED_INT, 0);
      glBindVertexArray(0);
     
      useBuffer = 1 - useBuffer;
   }


In the above code we call glBindVertexArray(vertexArrayHandle[useBuffer]), to bind the VAO we wish to use. Now I'm wondering when I make this call is it executing the commands set up in the init VAO method?

Maybe I'm thinking about this wrong but if it is calling them in order, replaying those commands. How does one change the Buffer data on the fly?
For example I know this does not work but I'm hoping this will make sense out of what I'm asking

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
public void endRender()
   {
      //Use the shader program
     glUseProgram(shaderProgramHandle);
     
      //Get the Uniform for the MVP shader
     glUniformMatrix4(matrixBufferHandle, false, mvpBuffer);
     
      //Enable the VAO and its attributes
     glBindVertexArray(vertexArrayHandle[useBuffer]);

           
                //Does not work but the idea of doing this. How?
               //Bind the buffer handle and VBO to use
     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle[useBuffer]);
      glBufferData(GL_ARRAY_BUFFER, vertexBuffer[useBuffer], GL_STREAM_DRAW);


      GL11.glDrawElements(GL_TRIANGLES, indexDrawCount, GL11.GL_UNSIGNED_INT, 0);
      glBindVertexArray(0);
     
      useBuffer = 1 - useBuffer;
   }

Offline theagentd
« Reply #7 - Posted 2014-01-13 16:01:47 »

In the above code we call glBindVertexArray(vertexArrayHandle[useBuffer]), to bind the VAO we wish to use. Now I'm wondering when I make this call is it executing the commands set up in the init VAO method?
To some extent, yes. Your approach when having multiple VBOs is correct. It's supposed to be faster than manually setting up your vertex attributes each time you want to render.

In the above code we call glBindVertexArray(vertexArrayHandle[useBuffer]), to bind the VAO we wish to use. Now I'm wondering when I make this call is it executing the commands set up in the init VAO method?

Maybe I'm thinking about this wrong but if it is calling them in order, replaying those commands. How does one change the Buffer data on the fly?

VAOs do not store all commands. Actually, they don't even store the actual glBindBuffer() commands. (EDIT: Not entirely true. They DO remember which index buffer is bound.) They only store the vertex attributes commands. That'd be glEnableVertexAttribArray() and glVertexAttribPointer(). The first one of course only enables a specific vertex attribute, but the second one is a bit more complicated. glVertexAttribPointer() reads from the currently bound GL_ARRAY_BUFFER buffer. When the VAO is bound again, it doesn't actually call glVertexAttribPointer() again. It remembers which buffer was bound when the VAO was created and uses that one again regardless of which one is bound when the VAO is bound for rendering. Binding the VAO doesn't bind any new buffers or anything like that.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
   public void endRender()
   {
      //Use the shader program
     glUseProgram(shaderProgramHandle);
     
      //Get the Uniform for the MVP shader
     glUniformMatrix4(matrixBufferHandle, false, mvpBuffer);
     
      //Enable the VAO and its attributes
     glBindVertexArray(vertexArrayHandle[useBuffer]);

      glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle[useBuffer]);
      glBufferData(GL_ARRAY_BUFFER, vertexBuffer[useBuffer], GL_STREAM_DRAW);


      GL11.glDrawElements(GL_TRIANGLES, indexDrawCount, GL11.GL_UNSIGNED_INT, 0);
      glBindVertexArray(0);
     
      useBuffer = 1 - useBuffer;
   }


There's nothing wrong with this code. Updating the data of a buffer does not affect the VAO in any way. Neither glBindBuffer() or glBufferData() modify the VAO, so you can update the buffer at any time, even when the VAO is not bound. The VAO just knows which buffers should be read and how the data should be interpreted, not the actual data in the buffer.

EDIT: More information: https://www.opengl.org/wiki/Vertex_Specification#Vertex_Array_Object
Quote
Think of it like this. glBindBuffer​ sets a global variable, then glVertexAttribPointer​ reads that global variable and stores it in the VAO. Changing that global variable after it's been read doesn't affect the VAO. You can think of it that way because that's exactly how it works.
This is also why GL_ARRAY_BUFFER​ is not VAO state; the actual association between an attribute index and a buffer is made by glVertexAttribPointer​.
Quote
The index buffer binding is stored within the VAO. If no VAO is bound, then you cannot bind a buffer object to GL_ELEMENT_ARRAY_BUFFER​.

Myomyomyo.
Offline noodleBowl

Senior Newbie





« Reply #8 - Posted 2014-01-14 03:25:02 »


There's nothing wrong with this code. Updating the data of a buffer does not affect the VAO in any way. Neither glBindBuffer() or glBufferData() modify the VAO, so you can update the buffer at any time, even when the VAO is not bound. The VAO just knows which buffers should be read and how the data should be interpreted, not the actual data in the buffer.


I was kinda hoping you'd come back and say yes haha

The reason I asked if it was wrong and if the VAO bind replayed commands is because nothing appears on my screen with that code. It would make sense if that was the case, since it would have already looked at the VBO bound.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
//Code that does not render the quad(s) to the screen
public void render()
{
      //Use the shader program
     glUseProgram(shaderProgramHandle);
     
      //Get the Uniform for the MVP shader
     glUniformMatrix4(matrixBufferHandle, false, mvpBuffer);
     
      //Enable the VAO and its attributes
     glBindVertexArray(vertexArrayHandle[useBuffer]);
     
                //Attempt to bind data to the VBO; Not sure why this fails to draw anything on screen
     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle[useBuffer]);
      glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STREAM_DRAW);
     
      GL11.glDrawElements(GL_TRIANGLES, indexDrawCount, GL11.GL_UNSIGNED_INT, 0);
      glBindVertexArray(0);
     
      useBuffer = 1 - useBuffer;
   }


I can only get something on my screen if I use my 'static' (Called before anything; in a class constructor) init method, where glBindBuffer and glBufferData are inside

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  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
public void initDebugBuffers()
   {
     
      vertexBuffer.clear();
      int x = 0;
      int y = 0;
     
      Random random = new Random();
     
      //X and Ys for the Quad; The Z is set to 1.0f
     for(int i = 0; i < MAX_QUADS; i++)
      {
         x = random.nextInt(800);
         y = random.nextInt(600);
         draw(x, y, 32, 32);
      }
     
      //Flip the buffer
     vertexBuffer.flip();
     
      //Bind the vertex buffer's data
    //Gets Quad to appear on screen, flickers but that is because we are only
    //binding the data to one of the two VBOs. (vertexBuffer data is used in both handles)
    //The VBO handles point to the same data spot; done for test purposes
    //Comment out and nothing will appear on screen (the buffer binds are in the render
    //method when the below is commented out)
     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle[0]);
      glBufferData(GL_ARRAY_BUFFER, vertexBuffer, GL_STATIC_DRAW);

      //Indices for the Quad
     indexDrawCount = MAX_INDEX_COUNT;
      indexBuffer.clear();
     
      for(int i = 0, j = 0;  i < MAX_QUADS; i++, j+= 4)
      {
         indexBuffer.put(j);
         indexBuffer.put(j + 1);
         indexBuffer.put(j + 2);
         indexBuffer.put(j + 3);
         indexBuffer.put(j);
         indexBuffer.put(j + 2);
      }
      indexBuffer.flip();
     
      //Bind the index buffer's data
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
      glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);

     
   }


Am I'm missing something? The only thing that I can think of is that my VBO handles in my init VAO method are not set up right. That they are pointing to invalid data. But that really does not make much sense to me either since I can bind the data in the static method, where at that point both VAOs are disabled

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
   private void initializeVAO()
   {
      //Bind the first VAO
     glBindVertexArray(vertexArrayHandle[0]);
      glEnableVertexAttribArray(0);
      glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle[0]); //The first Vertex Buffer handle that should be used
     glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
      glBindVertexArray(0);
     
      //Bind the second VAO
     glBindVertexArray(vertexArrayHandle[1]);
      glEnableVertexAttribArray(0);
      glBindBuffer(GL_ARRAY_BUFFER, vertexBufferHandle[1]); //The second Vertex Buffer handle that should be used
     glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferHandle);
      glBindVertexArray(0);
   }

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

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

The first screenshot will be displayed as a thumbnail.

TehJavaDev (18 views)
2014-08-28 18:26:30

CopyableCougar4 (26 views)
2014-08-22 19:31:30

atombrot (39 views)
2014-08-19 09:29:53

Tekkerue (36 views)
2014-08-16 06:45:27

Tekkerue (33 views)
2014-08-16 06:22:17

Tekkerue (22 views)
2014-08-16 06:20:21

Tekkerue (33 views)
2014-08-16 06:12:11

Rayexar (70 views)
2014-08-11 02:49:23

BurntPizza (47 views)
2014-08-09 21:09:32

BurntPizza (38 views)
2014-08-08 02:01:56
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!