OK, so I made a library that handles basic OpenGL rendering. It contains three buffers, one for vertices, uv's and normals. In the main render function is where I bind the buffers, enable vertex attributes, and then call glDrawArrays(). But I ran into an unexpected issue that is more engineering based then code based which is that I can only bind one texture at a time. So all the vertices will have the same textures when I draw them, How can I get around this? If you need any more source I will post it.
Main Render Function
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,this->_VBO);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER,this->_TBO);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER,this->_NBO);
glDrawArrays(GL_TRIANGLES,0,this->polyCount);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
Buffers:
//Designated Vertex Buffer
std::array<GLfloat,BUFFER_SIZE> BUFFER_1;
UINT bufferIndex1;
//Designated Normal Buffers
std::array<GLfloat,BUFFER_SIZE> BUFFER_2;
UINT bufferIndex2;
//Designated UV Buffer
std::array<GLfloat,BUFFER_SIZE> BUFFER_3;
UINT bufferIndex3;
What we would normally do here is split the mesh up into sub-meshes, by "material". An object with a different texture is technically a different material, so you would render it separately. You can render a single mesh using multiple textures by using something called an Atlas. That is to say, you pack your textures into a single bitmap and choose texture coordinates within that bitmap depending on the texture you want to use.
Related
I am using two shaders to render all the items in my scene. Each item is drawn by one shader only.
Every shader has different attributes. In my case, one shader has only vertex coordinates and color, while the second shader has vertex coordinates, texture coordinates and color.
Each shader has a VAO corresponding with these attributes.
What I do to render the scene is loop through all shaders. For each shader, I call glUseProgram, I call glBindVertexArray with the VAO associated with the shader and also initialize the attributes. Then once the shader is active I loop through all the items in my scene to render them with the current shader.
Now to simplify each item has a draw method which contains the following:
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
//s->setupVertices();
glDrawElements(m_primitive, m_elementSize, GL_UNSIGNED_INT, (GLvoid*)(sizeof(GLuint) * 0));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
If I run the program like this, the items are not rendered correctly, but I noticed that if I uncomment the setupVertices() line (this is where the glVertexAttribPointer for the current shader are called), then everything is rendered fine.
Now this is something I don't understand. From what I understood on VAO, VAO store information on the vertex attributes, so I was expecting that once I call glBindVertexArray with the current VAO, the data for the vertex layout are remembered correctly and there's no need to re-specify the vertices layout for each buffer object; but it looks like this is necessary otherwise all items are rendered wrongly.
Am I doing something wrong/missing? Or I didn't understand a bit about VAO/VBO work?
I'm following basic tutorial on OpenGL 3.0. What is not clear to me why/if I have to bind, enable and unbind/disable all vertex buffers and textures each frame.
To me it seems too much gl**** calls which I guess have some overhead. For example here you see each frame several blocks like:
// do this for each mesh in scene
// vertexes
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glVertexAttribPointer( 0, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// normals
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, normal_buffer );
glVertexAttribPointer( 1, 3, GL_FLOAT,GL_FALSE,0,(void*)0);
// UVs
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, uv_buffer );
glVertexAttribPointer( 2, 2, GL_FLOAT,GL_FALSE,0,(void*)0);
// ...
glDrawArrays(GL_TRIANGLES, 0, nVerts );
// ...
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
imagine you have not just one but 100 different meshes each with it's own VBOs for vertexes,normas,UVs. Should I really do this procedure each frame for each of them? Sure I can encapsulate that complexity into some function/objects, but I worry about overheads of this gl**** function calls.
Is it not possible some part of this machinery to move from per frame loop into scene setup ?
Also I read that VAO is a way how to pack corresponding VBOs for one object together. And that binding VAO automatically binds corresponding VBOs. So I was thinking that maybe one VAO for each mesh (not instance) is how it should be done - but according to this answer it does not seems so?
First things first: Your concerns about GL call overhead have been addressed with the introduction of Vertex Array Objects (see #Criss answer). However the real problem with your train of thought is, that you equate VBOs with geometry meshes, i.e. give each geometry its own VBO.
That's not how you should see and use VBOs. VBOs are chunks of memory and you can put the data of several objects into a single VBO; you don't have to draw the whole thing, you can limit draw calls to subsets of a VBO. And you can coalesce geometries with similar or even identical drawing setup and draw them all at once with a single draw call. Either by having the right vertex index list, or by use of instancing.
When it comes to the binding state of textures… well, yeah, that's a bit more annoying. You really have to do the whole binding dance when switching textures. That's why in general you sort geometry by texture/shader before drawing, so that the amount of texture switches is minimized.
The last 3 or 4 generations of GPUs (as of late 2016) do support bindless textures though, where you can access textures through a 64 bit handle (effectively the address of the relevant data structure in some address space) in the shader. However bindless textures did not yet make it into the core OpenGL standard and you have to use vendor extensions to make use of it.
Another interesting approach (popularized by Id Tech 4) is virtual textures. You can allocate sparsely populated texture objects that are huge in their addressable size, but only part of them actually populated with data. During program execution you determine which areas of the texture are required and swap in the required data on demand.
You should use vertex array object (generated by glGenVertexArrays). Thanks to it you don't have to perform those calls everytime. Vertex buffer object stores:
Calls to glEnableVertexAttribArray or glDisableVertexAttribArray.
Vertex attribute configurations via glVertexAttribPointer.
Vertex buffer objects associated with vertex attributes by calls to
glVertexAttribPointer.
Maybe this will be better tutorial.
So that you can generate vao object, then bind it, perform the calls and unbind. Now in drawing loop you just have to bind vao.
Example:
glUseProgram(shaderId);
glBindVertexArray(vaoId);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glUseProgram(0);
I would like to bind for example 80 textures on one mesh and put it in my VBO.
How can I achieve this?
I've read glActiveTexture is able to do that, however it allows max around 32 textures (GPU dependant).
My VBO code:
//Generating VBO
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d) + textureCoords.size()*sizeof(Vector2d), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size()*sizeof(Vector3d), vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vector3d), textureCoords.size()*sizeof(Vector2d), textureCoords.data());
glGenBuffers(1, &IND);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
//Drawing VBO:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexPointer(3, GL_DOUBLE, 0, 0);
glTexCoordPointer(2, GL_DOUBLE, 0, (void*)(vertices.size()*sizeof(Vector3d)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IND);
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void*)0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
Binding many (100s of) textures
I'm not sure of a way to bind that many separate textures at once. There are bindless textures but I don't have much experience with that extension. You could also use an array texture if many of your textures are the same size. But the standard approach to this problem is to use a texture atlas, where you pack lots of textures into the one, record where they're placed and adjust the texture coordinates to match.
Update: you could also use many texture arrays to store texture atlases (see comments and #Ethan's answer).
Applying multiple textures to a mesh
How will I tell the VBO, what faces will have which texture?
I think a more immediate problem is is how you go about applying different textures (or materials) to the same mesh. There's a few things to consider...
The most common case for applying multiple textures is where each stores a different material attribute but they all use the same texture coordinates/"UVs". E.g. diffuse, normal, specular maps. I guess in the extreme case when you have 100s of different attributes is where you'd want an array texture.
If each texture needs to be mapped differently you'd have a separate per-vertex texture coordinate VBO for each texture. Then you'll have to decide how the textures interact or blend as they're applied.
You have completely separate materials/texture per face. Commonly there are only a few materials on the mesh. The way you render it is in separate batches, grouping by material. Bind the right texture, set the shader uniforms, draw triangle indices A to B.
If nearly every face has a different material. I guess this might be the case if you're drawing a tile based game with lots of different tiles.
The problem here is the number of draw calls becomes a bottleneck,
so you'll have to combine different materials into the same draw call.
You could do this by storing the material on vertex attributes, such as adding a vertex colour VBO.
Rather than just colour, you could store a per-vertex texture ID, and if you're using a texture atlas, the region in the atlas where your texture can be found.
This starts to get inefficient because you'll have the same material data stored multiple times on each vertex of your triangles.
To minimize the overhead, you could store a material index per vertex, which points to a material defined in a table somewhere (either in a small uniform array, or if you need more materials, another texture).
Then add texture ID and atlas region to the material in the table.
Hopefully this last point answers your question.
To be honest, if you have more than 32 textures for one mesh, you probably have a much bigger problem than binding issues. But if you insist on having that many textures, you have 2 options: Bindless or Texture array. However, there are drawbacks: Bindless will limit your hardware support. Texture array does require the textures to be of the same size and format. Personally I think Texture Array is a workable solution. You can try to resize your textures if possile, then group those with the same size & format into one array. Now, you have 32 arrays to work with, and that should be more than enough, e.g. one array for all albedo textures, one for all normal maps etc. Regarding resizing, consider scaling textures up to the largest size that you have, or maybe split into categories e.g. small, medium, large. Avoid arbitrary sizes.
I'm using OpenGL 4 and C++11.
Currently I make a whole bunch of individual calls to glDrawElements using separate VAOs with a separate VBO and an IBO.
I do this because the texture coords change for each, and my Vertex data features the texture coords. I understand that there's some redundent position information in this vertex data; however, it's always -1,-1,1,1 because I use a translation and a scale matrix in my vertex shader to then position and scale the vertex data.
The VAO, VBO, IBO, position and scale matrix and texture ID are stored in an object. It's one object per quad.
Currently, some of the drawing would occur like this:
Draw a quad object via (glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT,0)). The bound VBO is just -1,-1,1,1 and the IBO draws me a quad. The bound VBO contains the texture coords of a common texture (same texture used to texture all drawn quads). Matrix transformations on shader position it.
Repeat with another quad object
glEnable(GL_SCISSOR_TEST) is called and the position information of the preview quad is used in a call to glScissor
Next quad object is drawn; only the parts of it visible from the previous quad are actually shown.
Draw another quad object
The performance I'm getting now is acceptable but I want it faster because I've only scratched the surface of what I have in mind. So I'm looking at optimizing. So far I've read that I should:
Remove the position information from my vertex data and just keep texture coords. Instead bind a single position VBO at the start of drawing quads so it's used by all of them.
But I'm unsure how this would work? Because I can only have one VBO active at any one time.
Would I then have to call glBufferSubData and update the texture coordinates prior to drawing each quad? Would this be better performance or worse (a call to glBindVertexArray for every object or a call to glBufferSubData?)
Would I still pass the position and scale as matrices to the shader, I would I take that opportunity to also update the position info of the vertices as well as the texture coords? Which would be faster?
Create one big VBO with or without an IBO and update the vertex data for the position (rather than use a transformation and scale matrix) of each quad within this. It seems like this would be difficult to manage.
Even if I did manage to do this; I would only have a single glDraw call; which sounds fast. Is this true? What sort of performance impact does a single glBindVertexArray call have over multiple?
I don't think there's any way to use this method to implement something like the glScissor call that I'm making now?
Another option I've read is instancing. So I draw the quad however many times I need it; which means I would pass the shader an array of translation matrices and an array of texture coords?
Would this be a lot faster?
I think I could do something like the glScissor test by passing an additional array of booleans which defines whether the current quad should be only drawn within the bounds of the previous one. However, I think this means that for each gl_InstanceID I would have to traverse all previous instances looking for true and false values, and it seems like it would be slow.
I'm trying to save time by not implementing all of these individually. Hopefully an expert can point me towards which is probably better. If anyone has an even better idea, please let me know.
You can have multiple VBO attached to different attributes!
following seqence binds 2 vbos to attribs 0 & 1, note that glBindBuffer() binds buffer temporarily and actual VBO assignment to attrib is made during glVertexAttribPointer().
glBindBuffer(GL_ARRAY_BUFFER,buf1);
glVertexAttribPointer(0, ...);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,buf2);
glVertexAttribPointer(1, ...);
glEnableVertexAttribArray(1);
The fastest way to provide quad positions & sizes is to use texture and sample it inside vertex shader. Of course you'd need at least RGBA (x,y,width,height) 16bits / channel texture. But then you can update quad positions using glTexSubImage2D() or you could even render them via FBO.
Everything other than that will perform slower, of course if you want we can elaborate about using uniforms, attribs in vbos or using attribs without enabled arrays for them.
Putting all together:
use single vbo, store quad id in it (int) + your texturing data
prepare x,y,w,h texture, define mapping from quad id to this texture texcoord ie: u=quad_id&0xFF , v=(quad_id>>8) (for texture 256x256 max 65536 quads)
use vertex shader to sample displacement and size from that texture (for given quad_id stored in attribute (or use vertex_ID/4 or vertex_ID/6)
fill vbo and texture
draw everything with single drawarrays of draw elements
In OpenGL, is there a way to use framebuffer data as vertex data without moving the data through the CPU? Ideally, a framebuffer object could be recast as a vertex buffer object directly on the GPU. I'd like to use the fragment shader to generate a mesh and then render that mesh.
There's a couple ways you could go about this, the first has already been mentioned by spudd86 (except you need to use GL_PIXEL_PACK_BUFFER, that's the one that's written to by glReadPixels).
The other is to use a framebuffer object and then read from its texture in your vertex shader, mapping from a vertex id (that you would have to manage) to a texture location. If this is a one-time operation though I'd go with copying it over to a PBO and then binding into GL_ARRAY_BUFFER and then just using it as a VBO.
Just use the functions to do the copy and let the driver figure out how to do what you want, chances are as long as you copy directly into the vertex buffer it won't actually do a copy but will just make your VBO a reference to the data.
The main thing to be careful of is that some drivers may not like you using something you told it was for vertex data with an operation for pixel data...
Edit: probably something like the following may or may not work... (IIRC the spec says it should)
int vbo;
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, vbo);
// use appropriate pixel formats and size
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo);
// draw stuff
Edited to correct buffer bindings thanks Phineas
The specification for GL_pixel_buffer_object gives an example demonstrating how to render to a vertex array under "Usage Examples".
The following extensions are helpful for solving this problem:
GL_texture_float - floating point internal formats to use for the color buffer attachment
GL_color_buffer_float - disable automatic clamping for fragment colors and glReadPixels
GL_pixel_buffer_object - operations for transferring pixel data to buffer objects
If you can do your work in a vertex/geometry shader, you can use transform feedback to write directly into a buffer object. This also has the option of skip the rasterizer and fragment shading.
Transform feedback is available as EXT_transform_feedback or core version since GL 3.0 (and the ARB equivalent).