Programs, VAOS, VBOS, multiple shaders - opengl

I am thinking of a scenario, in which,
while pressing a button, a different shader is used for a certain object.
So, I was wondering about memory handling in the gpu.
I usually have been using glUseProgram before any glBufferData call,
as I usually have been associating an object with a program.
I am in need of more flexibility now. I was wondering, does glBufferData
fill a memory location in the GPU, which any program can access?
Or does glUseProgram have to be called 1st, for the memory to be allocated
for that certain program?
I don't want to be passing the same data twice, once for each program.
Is a VAO likewise associated with a certain program?
It seems to me that they should be irrelevant. Since glGetAttribLocation
takes the program ID as an argument, that should be enough to specify
an object's attributes in a specific program.
However, in that case, I'm not even sure why glUseProgram is used at all.

Let's say you want to draw a car. You have a program (say, idP1 = 1) which uses VBO buffers buf1 and buf2 and attributes at1, at2. You store in a VAO (say, vao1) the needed bindings buf1 and buf2 to at1 and at2. Before you activate the drawing you active vao1 and "use" program idP1.
Now you want to draw a house. It has its own buffer buf3 and at1 attribute (yes, the same as for the car). You set a VAO (vao2) for the buf3 binding to at1. And it happens that the shader program is the same as for the car. No problem. You active vao2 and use idpP1. The shader will read at1 from buf3. at2 will not be used.
Now you want to draw a super-car. This needs a different shader. Buffers are the same as for a normal car, buf1, buf2, plus a new buf4. And they are readed in the shader the same way. Let's say by attributes at1, at2, at3. So you set a new VAO vao3, which sets bindings and attributes, perhaps for different locations in the shader. When you use this new program (idP2) it reads buf1 with at1, buf2 with at2 and buf4 with at3.
Notice that buffers are filled only once (or serveral, depending on how they change). You can create and fill a buffer when it's needed, not necessary at VAO creation. But VAO needs at least that the buffer is created before.

Related

Using the same vertex array object for different shader programs

my goal is to pack all mesh data into a C++ class, with the possibility of using an object of such a class with more than one GLSL shader program.
I've stuck with this problem: if I understand it well the way of how in GLSL vertex data are passed from CPU to GPU is based on using Vertex Array Objects which:
are made of Vertex Buffer Objects which store raw vertex data, and
Vertex Attribute Pointers which tells what shader variable location to assign and the format of the data passed to VBO above
additionally one can make an Element Buffer Object to store indices
another extra elements necessary to draw an object are textures which are made separately
I's able to make all that data and store only a VAO in my mesh class and only pass the VAO handler to my shader program to draw it. It works, but, for my goal of using multiple shader programs, the VAP stands in my way. It is the only element in my class that rely on a specific shader program's property (namely the location of input variables).
I wonder if I'm forced to remake all VAOs every time I'm using my shaders when I want to draw something. I'm afraid that the efficiency of my drawing code will suffer drastically.
So, I'm asking if I should forget of making my universal mesh class and instead make a separate objects for each shader program I'm using in my application. I would rather not, as I want to avoid unnecessary copying of my mesh data. On the other hand if this means my drawing routine will slow down because of all that remaking VAOs every milisecond during drawing then I have to rethink the design of my code :(
EDIT: OK I've misunderstood that VAOs store bindings to other objects, not the data itself. But there is one thing still left: to make an VAP I have to provide information about the location of an input variable from a shader and also the layout of data in VBO from a mesh.
What I'm trying to avoid is to make an separate object that stores that VAP which relies both on a mesh object and a shader object. I might solve my problem if all shader programs use the same location for the same thing, but at this moment I'm not sure if this is the case.
additionally one can make an Element Buffer Object to store indices
another extra elements necessary to draw an object are textures which are made separately
Just to be clear, that's you being lazy and/or uninformed. OpenGL strongly encourages you to use a single buffer for both vertex and index data. Vulkan goes a step further by limiting the number of object names (vao, vbo, textures, shaders, everything) you can create and actively punishes you for not doing that.
As to the problem you're facing.. It would help if you used correct nomenclature, or at least full names. "VAP" is yet another sign of laziness that hides what your actual issue is.
I will mention that VAOs are separate from VBOs, and you can have multiple VAOs linked to the same VBO (VBOs are just buffers of raw data -- again, Vulkan goes a step further here and its buffers store literally everything from vertex data, element indices, textures, shader constants etc).
You can also have multiple programs use the same VAOs, you just bind whatever VAO you want active (glBindVertexArray) once, then use your programs and call your render functions as needed. Here's an example from one of my projects that uses the same terrain data to render both the shaded terrain and a grid on top of them:
chunk.VertexIndexBuffer.Bind();
// pass 1, render the terrain
terrainShader.ProgramUniform("selectedPrimitiveID", selectedPrimitiveId);
terrainShader.Use();
roadsTexture.Bind();
GL.DrawArrays(PrimitiveType.Triangles, 0, chunk.VertexIndexBuffer.VertexCount);
// pass 2, render the grid
gridShader.Use();
GL.DrawElements(BeginMode.Lines, chunk.VertexIndexBuffer.IndexCount, DrawElementsType.UnsignedShort, 0);

Do I need a VAO for each different object rendered?

I believe I misunderstood the limits of VAO's.
I have 3 VAO's, one for each vertex spec. format.
Focusing on the VAO intended for menus/quads rendering in homogeneous screen coordinates, how many buffers can I have connected to the same array index of a single VAO ?
Due to results in my program I am inclined to believe every separate instance rendered should have it's own VAO. However, I am still able to draw two instances using one VAO, although with incorrect results. (Cursor takes up fullscreen and position doesn't change, rendered overtop fullscreen TitleMenu).
I'm fairly certain I already know the answer is have a VAO for each instance with differing array buffer data, would just like confirmation I have rationalized this correctly.
Also, are the buffers bound to the VAO copied to the VAO and can be deleted?
Does a glVertexAttribPointer() need to be called again to update the information in a VAO ? Or is buffering data to the original buffer sufficient ?

OpenGL: preparing data to be sent to shaders confusion

I'm a bit confused as to how to set up my application to send data to my shaders and be drawn. I know that I have to generate a VAO, bind it, generate buffer objects, bind them, populate it with data and create an attribute pointer to reference the data in the buffer object, because the openGL red book told me to... but I don't actually know what is happening in the process. could someone explain the process of this step by step and explain what is happening; to clear this up for me, and anybody else who doesn't quite understand this process. Also what does the VAO actually do? I know I can just reference the data in a buffer object with an attribute pointer and it will work fine, so what's the point in a VAO?
A Vertex Array Object (VAO) is an object which contains a group of Vertex Buffer Objects and is designed to store the information for a complete rendered object or a complete render batch. If you wouldn't use VAOs, for each batch you would have to bind all the VBOs one by one. With all VBOs in the batch in a VAO, you would just have to bind the VAO once instead of binding all the VBOs.
A Vertex Buffer Object (VBO) is a memory buffer in the high speed memory of your video card designed to hold information about vertices. VBOs can store information such as normals, texcoords, vertices, etc. This is why you have to let the shaders know whats inside the VBO using attribute pointers. VBOs offer substantial performance gains over immediate mode rendering primarily because the data resides in the video device memory rather than the system memory and so it can be rendered directly by the video device.
You have to bind the VBOs or VAOs to let OpenGL know what you are going to draw with the next draw call or that you are going to work with certain VBOs and tell OpenGL to have them ready for use.

Drawing multiple models using multiple openGL VBO's

rather than post lots of code, I will phrase this question intuitively. I hope you understand what I am getting at.
I am making a game and in the code I have a model class that loads a model and sets up the VBO for it.
In the loading function, it generates a new VBO ID and loads the vertex data from a file into that buffer by binding it etc. (This works fine)
At the beginning of the program I make one model object and load a .obj file.
In the render function, I simply call the DrawArrays() function (with the neccessary extra stuff) and as I said, everything works fine as the model appears on the screen with no problems.
The problem however, is when I make two model objects at the beginning of the program and load a different .obj file into each one.
The issue is that when I play, only the second model is drawn on screen.
The problem is because I don't properly understand how VBO's work.
This is how I "think" VBO's work.
You can generate as many VBO ID's as you want.
You can bind each ID to make it the active buffer.
You can load vertex data into that buffer.
You now effectively have many different ID's each referring to a "set of vertex data".
By calling the DrawArray function it draws every buffer you have generated (effectively displaying all your models on screen)
Now I know this is wrong because in my limited understanding I can't see how I could turn models on/off. But no matter how many tutorials I look at I can't answer this question because they all focus on displaying that ONE FIRST VBO, which incidentally I can do.
So... if that made sense, could anyone enlighten me?
You're doing it mostly right, but the drawing command does not draw every buffer you have generated. If you want to draw 2 objects with data in different buffers, you'll have to issue 2 drawing commands.
Let me explain, based on how I do it:
You create buffers using glGenBuffers. Before you can use a buffer, you have to "bind" it, that is, make it active using glBindBuffer. When a buffer is active, you can do stuff with it (populate with data for example). Note that there are different bind targets, so you can, for example, have one active array buffer (for vertex data) and one active element array buffer (for index data).
When you want to draw stuff, you have to specify what exactly you want to draw (I'll assume now that you're using your own shader) Usually you specify at least your vertex data and index data. To do this, you first bind your buffer with your vertex data (as an array buffer), then call glVertexAttribPointer with you attribute id. This tells OpenGL that the bound buffer is now the source for the current attribute. Then, you bind your index buffer as the element array buffer and call glDrawElements (not sure how glDrawArrays would work here).
You cannot use multiple VBOs at once for the same attribute - the call to bind another buffer just overwrites the previous call and makes the second buffer active, which, I assume, is why only your second object gets drawn.
You can also use VAOs to simplify the drawing - basically you assign an id to binding commands, then you can execute them with one line (think display lists).
So, my loading (of one object) looks like this:
Create buffers (let's say buffer 1 is for vertex data, buffer 2 for index data).
Bind buffer 1 as an array buffer.
Fill buffer with vertex data.
Repeat 2 and 3 for buffer 2 as element array buffer and index data, respectively.
And my drawing (again, of one object):
Bind buffer 1 as an array buffer.
Use glVertexAttribPointer to specify that this buffer goes to a specific attribute.
Bind buffer 2 as an element array buffer.
Call DrawElements
For the second object, you have to repeat everything.
Follow these steps to render your models, assuming model1 vertices are stored in vertexBuffer and model2 vertices in vertexBuffer2:
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, <no. of vert>);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer2);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, <no. of vert>);
//swap buffers depending on your windowing toolkit
Make sure to not perform glClear in the middle of the two model renders.
All the best!
what you want to do is set the vertexArrayAttribute back to the first object data before each call to drawArrays
the draw arrays function uses the bindings stored in the VAO to find the data needed to render everything
so to render 2 models you create a second VAO bind it and call glVertexAttribPointer as needed. for drawing you bind the VAO and call drawArrays for each model

structure of VBO state calls

I'm converting my OpenGL 2 program to OpenGL 3, one small step at a time. The current step is to get rid of immediate mode in favor of VBOs. I'm stumbling on the proper placement of all the VBO state management calls.
Let's assume I'm going to have a bunch of objects, each with its own VBOs for vertex and element data. Each object has a load function that sets up its VBOs and loads data into them; and it has a draw function that binds its VBOs and issues the appropriate draw command. To keep the objects from interfering with each other, my main loop should call PushClientAttrib(CLIENT_VERTEX_ARRAY_BIT) before either draw or load is called, correct? (And of course PopClientAttrib() after.)
When I push/pop that state to protect my load function, the object doesn't get drawn. It seems like there's some state I need to (re)set in my draw function, but I can't figure out what it could be.
Here's code to add a new object e to the scene, letting it call its load function:
gl.PushClientAttrib(gl.CLIENT_VERTEX_ARRAY_BIT)
e.SceneAdded()
gl.PopClientAttrib()
And here's how I call each object's draw function:
gl.PushClientAttrib(gl.CLIENT_VERTEX_ARRAY_BIT)
gl.PushMatrix()
p.Paint()
gl.PopMatrix()
gl.PopClientAttrib()
Here's the object's load function:
// Make the vertex & texture data known to GL.
gl.GenBuffers(1, &vboId)
gl.BindBuffer(gl.ARRAY_BUFFER, vboId)
gl.BufferData(gl.ARRAY_BUFFER,
gl.Sizeiptr(unsafe.Sizeof(gldata[0])*uintptr(len(gldata))),
gl.Pointer(&gldata[0].x), gl.STATIC_DRAW)
gl.VertexPointer(3, gl.DOUBLE, gl.Sizei(unsafe.Sizeof(gldata[0])),
gl.Pointer(unsafe.Offsetof(gldata[0].x)))
gl.TexCoordPointer(2, gl.DOUBLE, gl.Sizei(unsafe.Sizeof(gldata[0])),
gl.Pointer(unsafe.Offsetof(gldata[0].s)))
// Make the index data known to GL.
gl.GenBuffers(1, &iboId)
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, iboId)
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER,
gl.Sizeiptr(unsafe.Sizeof(sd.indices[0])*uintptr(len(sd.indices))),
gl.Pointer(&sd.indices[0]), gl.STATIC_DRAW)
Finally, here's the object's draw function:
func draw() {
gl.BindBuffer(gl.ARRAY_BUFFER, vboId)
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, iboId)
gl.EnableClientState(gl.VERTEX_ARRAY)
gl.EnableClientState(gl.TEXTURE_COORD_ARRAY)
gl.DrawElements(gl.TRIANGLES, indexcount, gl.UNSIGNED_SHORT, nil)
}
Just to be clear, if I move the two EnableClientState calls from draw to load, and if I don't protect load with PushClientState, everything works fine.
I'm converting my OpenGL 2 program to OpenGL 3
Well then the following
To keep the objects from interfering with each other, my main loop should call PushClientAttrib(CLIENT_VERTEX_ARRAY_BIT) before either draw or load is called, correct? (And of course PopClientAttrib() after.)
is not a sane approach. glPushAttrib and glPopAttrib are deprecated, i.e. should not be used in OpenGL-3 program.
Also OpenGL vertex arrays don't use glVertexPointer the use glVertexAttribPointer. Attribute pointer state can be managed (and I recommend that) in a Vertex Array Object, which you can bind/unbind.
BTW: When you wrote for OpenGL-2, why did you use immediate mode in the first place? Use of immediate mode is discouraged ever since OpenGL-1.1, when vertex arrays had been introduced. And already with OpenGL-2 it was considered to remove immediate mode.
The answer to the question I actually asked is that gl.VertexPointer() and friends need to be called from the object's draw function. My main loop is pushing and popping all state related to client vertices, so of course that gets lost.
The question I implied is, "How can I convert my old, GL2 program to new, GL3 code?" That's answered very elegantly here.