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.
Related
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);
I have a Sphere class that generate the VBO for creating given input radius and some more parameters.
Each Sphere VBO share the same memory layout (let's say vertex indice 0 = vertices, 1 = colors).
I may getting wrong, but if a understand correctly, state is what VAO store. But I don't know if VAO reminds which VBO was bound or use the currently bound VBO. But I think it use the VBO bound when modifying it (so it imply that reconfiguring the VAO for each Sphere render)
Question #1
Is it possible to store on VAO for all of the spheres? Sharing one VAO for multiple VBO.
Question #2
Can we set up the VAO independently from the VBO ? I wanna say, before even creating the VBO and without VBO bound, for example in a static function before even creating Spheres.
Question #3
This question may have non sens and be case-specific, but should I use one VAO and one VBO for each Sphere or share one VAO for all the Spheres (if it's possible) ?
Using the separate attribute format API, it is easy to set up a VAO independently from any particular set of source buffer objects. The vertex format information (component type, count, etc) can all be established via glVertexAttribFormat without a buffer object. You can even set up the relationship between attribute indices and buffer binding points, so that you can read interleaved attributes from a single buffer binding. All without ever binding a buffer object.
Now at the end of the data, you will have to attach buffer objects to the VAO when it comes time to render (via glBindVertexBuffer(s)). And the VAO will store the buffers it was last set with. But you should essentially ignore this. Treat a VAO as if it were just the vertex format state, with buffer binding being something that you do right before you render with it.
And yes, having one VAO and multiple potential buffers that get read with that vertex format (or better yet, just one buffer with multiple mesh data in it that all share the same vertex format, with mesh selection being done via the baseVertex parameter of glDrawElementsBaseVertex) is the right way to go.
All that being said, you also should remember that all spheres are the same mesh. They may appear in different locations with different sizes, but that's just a matter of providing a different transform of a unit sphere. The only reason to use more than one sphere mesh is if you need different resolutions of spheres (more polygons vs. fewer).
I have a really obscure problem that I hope somebody can help with. I have implemented vertex skinning on the CPU (the GPU was too slow because the bad performance of looking up a bone transform in a vertex shader) using a background thread on OSX. I do not need a shared context because no GL calls are made. I allocate a buffer in the process heap big enough to hold my character's vertices. I skin and animate that buffer on the background thread. In the main thread I simply glBufferSubData() that buffer down to my VBO, synchronizing with the end of the buffer update so I don't get tearing in my verts. The VBO has previously been bound to a VAO (one VAO per VBO per character instance). So I only have to bind the VAO and draw my mesh. Not very difficult so far. A single IBO is bound to all VAO's per character instance.
Here's the rub. If I only have one character instance the code works perfectly. I have a lovely little warrior princess doing her idle animation. The moment I add a second instance nothing happens--only the first instance renders.
So the big question is what am I doing wrong? I'm pretty sure my VBO, IBO and VAOs are correct. There's a separate VBO and VAO per instance. I turned off indexing (no IBO) and still the instances fail to draw so it's not that IMHO. I've verified the state using the Mac OpenGL Profiler and everything looks good per instance. Is there some kind of weird flushing not going on due to my glBufferSubData call. glMapBuffer was just too slow!
If you need source code to look at I can upload that easily enough. Just wondering if anyone's heard of weirdness like what I'm seeing when dealing with buffer objects in OpenGL on the Mac.
My computer doesn't support OpenCL on the GPU or OpenGL compute shaders so I was wondering if it would be a straight forward process to get data from a vertex or fragment shader?
My goal is to pass 2 textures to the shader and have the shader computer the locations where one texture exists in the other. Where there is a pixel match. I need to retrieve the locations of possible matches from the shader.
Is this plausible? If so, how would I go about it? I have the basic OpenGL knowledge, I have set up a program that draws polygons with colors. I really just need a way to get position values back from the shader.
You can render to memory instead of to screen, and then fetch data from it.
Create and bind a Framebuffer Object
Create a Renderbuffer Object and attach it to the Framebuffer Object
Render your scene. The result will end up in the bound Framebuffer Object instead of on the screen.
Use glReadPixels to pull data from the Framebuffer Object.
Be aware that glReadPixels, like most methods of fetching data from GPU memory back to main memory, is slow and likely unsuitable for real-time applications. But it's the best you can do if you don't have features intended for that, like Compute Shaders, or are willing to do it asynchronously with Pixel Buffer Objects.
You can read more about Framebuffers here.
So I'm trying to implement VBOs but I can't find a good tutorial or documentation of the proper usage of them. I'm guessing you make a VBO when some object needs it and then when the next frame comes about it's drawn/redrawn. But here is where I'm confused:
How do I draw multiple VBOs?
How do I modify a VBO?
When and where do I make a new VBO?
I'm really sorry and I'm just learning OpenGL so excuse me for that! But it's hard to find a tutorial that doesn't just make one VBO, and doesn't make that VBO at the same time it's drawn.
Mainly what I'm asking for is a better understanding of how VBOs work, where they are stored, and how they are drawn. How many VBOs is too many? When I call glVertexPointer() what exactly happens with stored VBOs? What if I'm trying to draw VBOs of different types? (just use triangles?)
How do I draw multiple VBOs?
VBOs are data storage, just like textures. There's a function called glBindBuffer which binds a VBO for subsequent access through glVertexAttribPointer.
How do I modify a VBO?
glBufferSubData
or
buf = glMapBuffer(...);
modify_on(buf);
glUnmapBuffer(...);
When and where do I make a new VBO?
Whenever the existing VBOs no longer can satisfy your demands. Either because they're to small, full or don't match your data type.