This question already has answers here:
Is it possible to in-place resize VBOs?
(3 answers)
Closed 2 years ago.
I am initializing a object with following code.
std::vector<float> topRightBevelData = draw_circular_bevel(rightWidth, rightHeight, rightTopBevel, 1, 1, iSegmentsRightTop);
glGenVertexArrays(1, &m_VAOTopRightCircle);
glGenBuffers(1, &m_VBOTopRightCircle);
glBindVertexArray(m_VAOTopRightCircle);
glBindBuffer(GL_ARRAY_BUFFER, m_VBOTopRightCircle);
glBufferData(GL_ARRAY_BUFFER, topRightBevelData.size() * sizeof(float), &topRightBevelData[0], GL_DYNAMIC_DRAW);
Than i would keep updating the VBO.
std::vector<float> topRightBevelData = draw_circular_bevel(xWidth / 2.0, 0.0, 0.0, rightWidth, rightHeight, rightTopBevel, 1, 1, iSegmentsRightTop);
glBindBuffer(GL_ARRAY_BUFFER, m_VBOTopRightCircle);
glBufferSubData(GL_ARRAY_BUFFER, 0 ,topRightBevelData.size() * sizeof(float), &topRightBevelData[0]);
Sometimes the data updating the vbo would be larger than the size of VBO , in that case can i increase the size of VBO ?
[...] can i increase the size of VBO ?
No. The size of a buffer (like a Vertex Buffer Object) is immutable. If you need a buffer with a greater size, then you have to recreate the buffer object by glBufferData.
I recommend creating a buffer that is large enough when initializing.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 days ago.
Improve this question
I've been trying to implement a particle simulation engine which computes forces between particles on GPU using CUDA and visualizes it using openGL. I've been stuck for some time on the part where I want to update my vertex buffer without copying it back to CPU. The problem seems to be in the way I'm binding/ passing the vertex buffer.
Here is the fragment of code that is responsible for creating VAO and VBO and drawing it to the screen:
// pointer to array on gpu
float* d_particlePositions;
// Creating a vertex array object
GLuint vertexArrayObject;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
// Creating a vertex buffer object for N points with 3 floats
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 3 * N * sizeof(float), NULL, GL_DYNAMIC_COPY);
cudaGLRegisterBufferObject(vertexBuffer);
// rendering loop
while(running){
cudaGLMapBufferObject((void **) &d_particlePositions, vertexBuffer);
// call some kernel functions like
update<<<x,y>>>(d_particlePositions, ...);
cudaGLUnmapBufferObject(vertexBuffer);
// bind VAO, VBO and draw to screen
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *) 0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_POINTS, 0, N);
}
I know that my openGL setup is right because i got it working, but in case when every cycle I had to copy it back to CPU and create a new VBO. If you have some resources that can help me solve this I' highly appreciate it.
Here is a sample code :-
unsigned int instanceVBO;
glGenBuffers(1, &instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBindVertexArray(VAO);
...
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * 100,
&translations[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
... ... ...
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribDivisor(2, 1); //<--- who own this setting?
//^ mostly copied from https://learnopengl.com/Advanced-OpenGL/Instancing
Who own the glVertexAttribDivisor setting? (VAO / instanceVBO / global state)
A comment in https://gamedev.stackexchange.com/questions/99236/what-state-is-stored-in-an-opengl-vertex-array-object-vao-and-how-do-i-use-the#comment174555_99238 suggests that it is stored in VBO.
However, the comment contradicts (?) to the above code which calls glVertexAttribDivisor(2, 1) after unbinds glBindBuffer(GL_ARRAY_BUFFER, 0); .
I would be appreciate if you are also kind to provide reference that I can read more about :
which settings/states owned by which one of Opengl's thingy (VAO/VBO/etc).
The vertex array divisor (VERTEX BINDING DIVISOR) is stored in the Vertex Array Objects state vector, separately for each vertex attribute (like enable state, offset, stride etc.).
The states which are stored in the VAO are listed in the specification in Table 23.3: Vertex Array Object State.
VAOs are specified in OpenGL 4.6 API Core Profile Specification - 10.3.1 Vertex Array Objects.
See also Vertex Specification - Instanced arrays
I'm currently learning OpenGL in my free time and lately I have been facing an "error" I don't understand.
The thing is, I have no errors, only nothing appear on my screen. I'm using OpenGL with SFML.
Here is my code. Here is my method:
void CreateObjet(GLuint& vao, GLuint& vbo, GLuint& ebo, GLuint& textureLocation)
//I create my arrays here.. Don't worry they are fine.
CreateTexture(textureLocation);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glGenVertexArrays (1, &vao);
glBindVertexArray (vao); //On travaille dans le VAO
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), NULL);
glEnableVertexAttribArray(0);
glBufferData (GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3* sizeof(GLfloat)));
glEnableVertexAttribArray(1);
glBufferData (GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW);
glVertexAttribPointer (2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6* sizeof(GLfloat)));
glEnableVertexAttribArray(2);
//EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indiceFinal), indiceFinal, GL_STATIC_DRAW);
glBindVertexArray(0);
I know my problem is not with my shaders because I receive no errors in my console with GlshaderRiv().
I would like to know if I'm doing the order properly.
I Create a VBO and a EBO
I Create a VAO
I bind the current VAO to modify it
I bind the current VBO inside the VAO
I bind my first array (Vertex Position vector3f) in my VBO and put them in the first pointer with the correct offset and stride.
I bind my second array (Color Position vector3f) in my VBO and put them in the first pointer with the correct offset and stride.
I bind my third array (Texture Position vector2f) in my VBO and put them in the first pointer with the correct offset and stride.
I bind a EBO within the VAO
I bind the EBO with my element position (Vector 3u).
I unbind the VAO from the memory because my drawing loop is quite later in the code and so, I don't want to use memory space for nothing. Don't worry, Before I draw I put glBindVertexArray(&vao);
That definitely does not look right. You're writing the values for all attributes to the same buffer, with each one overwriting the previous one:
glBufferData (GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), NULL);
glEnableVertexAttribArray(0);
glBufferData (GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
...
When you make the second glBufferData() call, it will overwrite the points data that you previously stored in the buffer with the colors data.
The misunderstanding is probably about what glVertexAttribPointer() does. It specifies which buffer the given attribute is sourced from, as well as the data layout (component count, type, etc). But it does not create a copy of the buffer data, or anything like that. The attribute data you want to use must still be stored in the buffer at the time of the draw call.
To fix this, you either have to use a different buffer for each attribute, or arrange the attribute data so that the values for all 3 attributes can be stored in the same buffer. The arguments of your glVertexAttribPointer() calls actually suggest that you were intending to store all attribute values interleaved in the same buffer. To get this working, you have to arrange the attribute values accordingly, and then store them in the buffer with a single glBufferData() call.
The memory arrangement you will need for this will have all the attribute values for the first vertex in sequence, followed by the values for the second vertex, etc. With pi the position of vertex i, ci the color, and ti the texture coordinates, the correct memory layout is:
p0x p0y p0z c0r c0g c0b t0s t0t
p1x p1y p1z c1r c1g c1b t1s t1t
p2x p2y p2z c2r c2g c2b t2s t2t
...
I am studying the source code of an open source project and they have a use of the function glDrawElements which I don't understand. While being a programmer, I am quite new to the GL API so would appreciate if someone could tell me how this works.
Let's start with the drawing part. The code looks like this:
for (int i = 0; i < numObjs; i++) {
glDrawElements(GL_TRIANGLES, vboIndexSize(i), GL_UNSIGNED_INT, (void*)(UPTR)vboIndexOffset(i));
}
vboIndiexSize(i) returns the number of indices for the current object, and vboIndexOffset returns the offset in bytes, in a flat memory array in which vertex data AND the indices of the objects are stored.
The part I don't understand, is the (void*)(UPTR)vboIndexOffset(i)). I look at the code many times and the function vboIndexOffset returns a int32 and UPTR also cast the returned value to an int32. So how you can you cast a int32 to a void* and expect this to work? But let's assume I made a mistake there and that it actually returns a pointer to this variable instead. The 4th argument of the glDrawElements call is an offset in byte within a memory block. Here is how the data is actually stored on the GPU:
int ofs = m_vertices.getSize();
for (int i = 0; i < numObj; i++)
{
obj[i].ofsInVBO = ofs;
obj[i].sizeInVBO = obj[i].indices->getSize() * 3;
ofs += obj[i].indices->getNumBytes();
}
vbo.resizeDiscard(ofs);
memcpy(vbo.getMutablePtr(), vertices.getPtr(), vertices.getSize());
for (int i = 0; i < numObj; i++)
{
memcpy(
m_vbo.getMutablePtr(obj[i].ofsInVBO),
obj[i].indices->getPtr(),
obj[i].indices->getNumBytes());
}
So all they do is calculate the number of bytes needed to store the vertex data then add to this number the number of bytes needed to store the indices of all the objects we want to draw. Then they allocate memory of that size, and copy the data in this memory: first the vertex data and then the indices. One this is done they push it to the GPU using:
glGenBuffers(1, &glBuffer);
glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
checkSize(size, sizeof(GLsizeiptr) * 8 - 1, "glBufferData");
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)size, data, GL_STATIC_DRAW);
What's interesting is that they store everything in the GL_ARRAY_BUFFER. They never store the vertex data in a GL_ARRAY_BUFFER and then the indices using a GL_ELEMENT_ARRAY_BUFFER.
But to go back to the code where the drawing is done, they first do the usual stuff to declare vertex attribute. For each attribute:
glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, size, type, GL_FALSE, stride, pointer);
This makes sense and is just standard. And then the code I already mentioned:
for (int i = 0; i < numObjs; i++) {
glDrawElements(GL_TRIANGLES, vboIndexSize(i), GL_UNSIGNED_INT, (void*)(UPTR)vboIndexOffset(i));
}
So the question: even if (UPTR) actually returns the pointer to variable (the code doesn't indicate this but I may be mistaken, it's a large project), I didn't know it was possible to store all vertex and indices data with the same memory block using GL_ARRAY_BUFFER and then using glDrawElements and having the 4th argument being the offset to the first element of this index list for the current object from this memory block. I thought you needed to use GL_ARRAY_BUFFER and GL_ELEMENT_BUFFER to declare the vertex data and the indices separately. I didn't think you could declare all the data in one go using GL_ARRAY_BUFFER and can't get it to work on my side anyway.
Has anyone see this working before? I haven't got a chance to get it working as yet, and wonder if someone could just potentially tell me if there's something specific I need to be aware of to get it to work. I tested with a simple triangle with position, normal and texture coordinates data, thus I have 8 * 3 floats for the vertex data and I have an array of 3 integers for the indices, 0, 1, 2. I then copy everything in a memory block, initialize the glBufferData with this, then try to draw the triangle with:
int n = 96; // offset in bytes into the memory block, fist int in the index list
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, (void*)(&n));
It doesn't crash but I can't see the triangle.
EDIT:
Adding the code that doesn't seem to work for me (crashes).
float vertices[] = {
0, 1, 0, // Vertex 1 (X, Y)
2, -1, 0, // Vertex 2 (X, Y)
-1, -1, 0, // Vertex 3 (X, Y)
3, 1, 0,
};
U8 *ptr = (U8*)malloc(4 * 3 * sizeof(float) + 6 * sizeof(unsigned int));
memcpy(ptr, vertices, 4 * 3 * sizeof(float));
unsigned int indices[6] = { 0, 1, 2, 0, 3, 1 };
memcpy(ptr + 4 * 3 * sizeof(float), indices, 6 * sizeof(unsigned int));
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 4 * 3 * sizeof(float) + 6 * sizeof(unsigned int), ptr, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
free(ptr);
Then when it comes to draw:
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// see stackoverflow.com/questions/8283714/what-is-the-result-of-null-int/
typedef void (*TFPTR_DrawElements)(GLenum, GLsizei, GLenum, uintptr_t);
TFPTR_DrawElements myGlDrawElements = (TFPTR_DrawElements)glDrawElements;
myGlDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, uintptr_t(4 * 3 * sizeof(float)));
This crashes the app.
see answer below for solution
This is due to OpenGL re-using fixed-function pipeline calls. When you bind a GL_ARRAY_BUFFER VBO, a subsequent call to glVertexAttribPointer expects an offset into the VBO (in bytes), which is then cast to a (void *). The GL_ARRAY_BUFFER binding remains in effect until another buffer is bound, just as the GL_ELEMENT_ARRAY_BUFFER binding remains in effect until another 'index' buffer is bound.
You can encapsulate the buffer binding and attribute pointer (offset) states using a Vertex Array Object.
The address in your example isn't valid. Cast offsets with: (void *) n
Thanks for the answers. I think though that (and after doing some research on the web),
first you should be using glGenVertexArray. It seems that this is THE standard now for OpenGL4.x so rather than calling glVertexAttribPointer before drawing the geometry, it seems like it's best practice to create a VAO when the data is pushed to the GPU buffers.
I (actually) was able to make combine the vertex data and the indices within the SAME buffer (a GL_ARRAY_BUFFER) and then draw the primitive using glDrawElements (see below). The standard way anyway is to push the vertex data to a GL_ARRAY_BUFFER and the indices to a GL_ELEMENT_ARRAY_BUFFER separately. So if that's the standard way of doing it, it's probably better not to try to be too smart and just use these functions.
Example:
glGenBuffers(1, &vbo);
// push the data using GL_ARRAY_BUFFER
glGenBuffers(1, &vio);
// push the indices using GL_ELEMENT_ARRAY_BUFFER
...
glGenVertexArrays(1, &vao);
// do calls to glVertexAttribPointer
...
Please correct me if I am wrong, but that seems the correct (and only) way to go.
EDIT:
However, it is actually possible to "pack" the vertex data and the indices together into an ARRAY_BUFFER as long as a call to glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo) is done prior to calling glDrawElements.
Working code (compared with code in original post):
float vertices[] = {
0, 1, 0, // Vertex 1 (X, Y)
2, -1, 0, // Vertex 2 (X, Y)
-1, -1, 0, // Vertex 3 (X, Y)
3, 1, 0,
};
U8 *ptr = (U8*)malloc(4 * 3 * sizeof(float) + 6 * sizeof(unsigned int));
memcpy(ptr, vertices, 4 * 3 * sizeof(float));
unsigned int indices[6] = { 0, 1, 2, 0, 3, 1 };
memcpy(ptr + 4 * 3 * sizeof(float), indices, 6 * sizeof(unsigned int));
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 4 * 3 * sizeof(float) + 6 * sizeof(unsigned int), ptr, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
free(ptr);
Then when it comes to draw:
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo); // << THIS IS ACTUALLY NOT NECESSARY
// VVVV THIS WILL MAKE IT WORK VVVV
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// see stackoverflow.com/questions/8283714/what-is-the-result-of-null-int/
typedef void (*TFPTR_DrawElements)(GLenum, GLsizei, GLenum, uintptr_t);
TFPTR_DrawElements myGlDrawElements = (TFPTR_DrawElements)glDrawElements;
myGlDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, uintptr_t(4 * 3 * sizeof(float)));
This question already has answers here:
What is the proper way to modify OpenGL vertex buffer?
(3 answers)
Closed 2 years ago.
Currently I'm writing a program that simulates water. Here are the steps that I do:
Create water surface - plane.
Create VAO
Create vertex buffer object in which I store normals and vertices.
Bind pointers to this VBO.
Create index buffer object.
Then I render this plane using glDrawElements and then I invoke an update() function which changes positions of vertices of water surface. After that I invoke glBufferSubData function to update vertices positions.
When I do that - nothing happens as if the buffer isn't changed.
Here's the code snippet:
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Oscillator) * nOscillators, oscillators, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Oscillator), 0);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Oscillator), (const GLvoid*)12);
glEnableVertexAttribArray(0); // Vertex position
glEnableVertexAttribArray(2); // normals position
glGenBuffers(1, &indicesBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * nIndices, indices, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
glBindVertexArray(0);
Then render:
glBindVertexArray(vaoHandle);
glDrawElements(GL_TRIANGLES, nIndices, GL_UNSIGNED_INT, 0);
update(time);
And update function:
//some calculations
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Oscillator) * nOscillators, oscillators);
Oscillator - it's a structure that has: 8 floats respectively - x, y, z (vertex position), nx, ny, nz (normals), upSpeed, newY
oscillators - this is an array of Oscillator structures.
What I do wrong?
Before updating the data you have to bind the correct buffer. E.g:
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
Since you are updating the full buffer at once I would suggest to use glMapBuffer to update it
void* data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
//[...] update the buffer with new values
bool done = glUnmapBuffer(GL_ARRAY_BUFFER);
And remember to wait (or force) a glFlush() before modifying the data you are goin to copy to the gl buffer.