What is the best way to store dynamic data for use in VBO (or vertex arrays). Only examples I saw were 2D static arrays and the pointer to that array was used with next parameters as stride, bytes used for one element etc. I can use "dynamic" arrays so I can specify it's size on-air, but just once. My point is that if you, for example, already drawing 1000 points (talking about 2D so I think point is better then vertex) as line strip and you add new point, this way you have to make new array with size of 1001, copy everything from old to new field, add new point and send it down to graphic's memory. Best way is to use vectors or deques as temporary storage, but then I have to convert to array and again send it down.
So is there better way to do this? Can I only add new part to VBO without sending down the old data? Or better way to store data/using vector as data source without conversion?
I usually just use the 'ole vector trick:
struct GL_Vertex
{
Eigen::Vector2f tex;
Eigen::Vector3f color;
Eigen::Vector3f pos;
};
...
vector<GL_Vertex> buf(1000);
...
glTexCoordPointer( 2, GL_FLOAT, sizeof(GL_Vertex), &buf[0].tex );
glColorPointer( 3, GL_FLOAT, sizeof(GL_Vertex), &buf[0].color );
glVertexPointer( 3, GL_FLOAT, sizeof(GL_Vertex), &buf[0].pos );
Related
I have a subfunction that reads a data stream and creates an array of vertex data based on that. The main function calls this subfunction repeatedly and updates the vertex data array, which is then bound to a buffer and drawn. So far, so good. However, I cannot figure out how to add vertices. C++ does not let you reassign or resize entire arrays. I can't use vectors because the OpenGL functions take in arrays, not vectors.
You can use vectors to populate an OpenGL vertex buffer. The values in a vector are guaranteed to be contiguous. See for example these discussions for details on the related language standards:
Are std::vector elements guaranteed to be contiguous?
Is it safe to assume that STL vector storage is always contiguous?
This means that code like the following is safe:
std::vector<GLfloat> vertexPositions;
// Populate vector with vertex positions.
GLuint bufId = 0;
glGenBuffers(1, &bufId);
glBindBuffer(GL_ARRAY_BUFFER, bufId);
glBufferData(GL_ARRAY_BUFFER, vertexPositions.size() * sizeof(GLfloat),
&vertexPositions[0], GL_STATIC_DRAW);
The subtle but critical part is that you pass in the address of the first element of the vector, not the address of the vector object.
I would make a slight edit. While you can use &vertexPositions[0] as the address of the beginning of an STL vector, I prefer to use the function designed to return the address of the beginning of the vector memory, vertexPositions.data().
std::vector<GLfloat> vertexPositions;
// Populate vector with vertex positions.
GLuint bufId = 0;
glGenBuffers(1, &bufId);
glBindBuffer(GL_ARRAY_BUFFER, bufId);
glBufferData(GL_ARRAY_BUFFER, vertexPositions.size() * sizeof(GLfloat), vertexPositions.data(), GL_STATIC_DRAW);
I use STL vectors for OGL data for a number of reasons. It's easy to preallocate if you know the size, and they will grow (and stay contiguous) when you add items. They are easy to iterate through. You can easily create vectors of structures if you want to pass in interleaved data. It all works the same.
I have particle and particle system class. In my main program, I created an instance of particle system and initialized the particles in it. In the display function, I would like to pass the position of all particles to the Vertex buffer in one shot. But I'm not sure of the notation used to access all position vertices from the.
class particle{
glm::vec3 pos;
glm::vec3 vel;
}
class particleSystem{
std::vector<particle> m_particles;
}
I tried something like this:
//Displaying particles starts here
glGenBuffers(1, &particleBuffers);
glBindBuffer(GL_ARRAY_BUFFER, particleBuffers);
glBufferData(GL_ARRAY_BUFFER, sizeof(ps.m_particles[].pos), ps.m_particles[].pos, GL_STATIC_DRAW);
glVertexAttribPointer(position_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_POINTS, 0, (GLsizei)ps.m_particles.size()); //Draw them to screen
glBindBuffer(GL_ARRAY_BUFFER, 0);
//Displaying particles ends here
where ps is an instance of the particlesystem class. The notation I used to access all positions of the particles in the glBufferData function does not work. Any suggestions?
I would consider uploading the entire particle vector to the GPU like this:
struct particle {
glm::vec3 pos;
glm::vec3 vel;
};
[...]
glBufferData (GL_ARRAY_BUFFER, sizeof (particle) * ps.m_particles.size (),
&ps.m_particles [0], GL_STATIC_DRAW);
glVertexAttribPointer (position_loc, 3, GL_FLOAT, GL_FALSE, sizeof (particle), 0);
I am not sure how your original code actually worked, these fields have private access by default if you declare particle as a class.
There are two points to mention here:
&ps.m_particles [0] is the standard method to acquire a pointer to a contiguous block of memory representing your vector's data store.
Since your particle data structure contains two fields, your stride is non-zero.
This is the second-to-last parameter in the call to glVertexAttribPointer (...).
Alternatively, you might consider a separate data structure to store the data you actually need for rendering from the data you need for CPU-side simulation:
struct particle_vtx {
glm::vec3 pos;
//glm::vec3 color;
};
struct particle_state {
glm::vec3 vel;
//GLuint texture;
};
[...]
class particleSystem {
std::vector<particle_vtx> m_particle_verts;
std::vector<particle_state> m_particle_states;
};
This is probably the more versatile solution in the end, because you will have two pools of contiguous memory that separate what the GPU needs from what the CPU needs. You will be much more memory efficient (on the GPU side) and will not require any special processing when it comes time to send the vertex data to the GPU. Granted stateful particle systems can be implemented completely on the GPU these days, start small.
You have to pass an integer value into the vector array operator. If you are trying to create an array of glm::vec3 to pass into glBufferData, you'll have to do so manually - probably through use of a for loop and dynamic allocation.
I have a struct to store vertex data for 2 distinct models one is a cube the other a pyramid.
struct Model{
GLuint vboID;
GLfloat* vbo;
GLuint vaoID;
GLfloat* vao;
GLuint vertexStart;
GLuint vertexCount;
};
I create the vbos and generate their buffers like this:
Model cubeModel;
Model pyramidModel;
cubeModel.vbo = cubeVerts; //A GLfloat array I created earlier in code earlier.
cubeModel.vertexCount= sizeof(cubeVerts);//size of the GLfloat array in bytes
pyramidModel.vbo = pyVerts;
pyramidModel.vertexCount= sizeof(pyVerts);
glGenBuffers(1, &cubeModel.vboID); //Generate a buffer for the vertices
glBindBuffer(GL_ARRAY_BUFFER, cubeModel.vboID); //Bind the vertex buffer
glBufferData(GL_ARRAY_BUFFER, cubeModel.vertexCount, cubeModel.vbo, GL_STATIC_DRAW);
And then to draw I use:
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, cubeModel.vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
Which works, and I successfully draw the cube, But i've been trying multiple ways to draw the pyramid as well.
What do I need to do to render both on screen at the same time?
EDIT: Here's what i've tried specifically, duplicating the glBufferData() call and passing in the pyramid data then making glDrawArays(GL_TRIANGLES,0,cubeModel.drawcount+pyramidModel.drawCount) figuring the vertex data would stack and glDrawArrays would go through all the geometry passed in one go.
I've also tried making 2 sets of instructions from glGenBuffers() to glDisableClientState() but instead using all of pyramid model's data. This was interesting because my glDrawArrays was:
glDrawArrays(GL_TRIANGLES, 0, cubeModel.drawCount);
glTranslatef(4.0f,0.0f,0.0f);
glDrawArrays(GL_TRIANGLES, 0, pyramidModel.drawCount);
and it ended up drawing a really messed up pyramid 2 times, leading me to believe that when I cal glBufferData() twice the second time Overwrites the data previously passed.
EDIT 2:After Reading Andon's comment I edited some of my code to clarify things, drawCount is now vertexCount, and m_vertexBuffer is now correctly referencing the handle I stored in cubeModel, cubeModel.vboID, instead of using an old class variable I was using to store the handle.
I do not want to muddy up the comments section, because there are a lot of things wrong with your code. But I also do not have time to go through all of them right now, so this is a sort of temporary answer.
glBufferData (...) does not technically overwrite previously passed data, it does something far worse. Every time you call glBufferData (...) it creates a new data store of the size you pass and (optionally) fills it with the data you supply (if you pass something non-NULL). Think of it more like calling free (...) and then malloc (...) or delete [] ... and new Type [...].
glBufferSubData (...) is the preferred technique for appending vertices to a vertex buffer. Unfortunately it does not resize the data store. Sometimes it is handy to over-allocate your VBO and defer supplying it data until later on (using glBufferSubData).
If you use one VBO to store both of your models, you need to know the starting vertex and the vertex count for each model as it relates to your VBO's data. Right now all you know is the number of vertices (and you have it named strangely drawCount instead of vertexCount). To most people, drawCount indicates the number of times you want to draw something, rather than the number of vertices or elements it contains.
The size field of a call to glBufferData (...) is supposed to be the size in bytes of your vertex data. Right now you're passing the number of vertices. More than likely you meant to use sizeof (YourVertexDataStructure) for the size of an individual vertex (sizeof (float [3]) in this case), and something like sizeof (cubeVerts) / sizeof (YourVertexDataStructure) to calculate the number of vertices actually stored in this array. Then the size you pass to glBufferData (...) would be: _size * count_
I'm using Eigen3 2-dimensional vector as 2D point for opengl drawing, storing them in a list:
typedef Eigen::Vector2d Vec2D;
std::list<Vec2D> points;
Now, I need an array of GLfloat to pass the entire data structure of raw float coordinate value to the graphic card:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
_vertex = new GLfloat[points.size()*2];
_colors = new GLfloat[points.size()*4];
std::list<Vec2D>::const_iterator it;
int i=0, j=0;
for(it=points.begin(); it!=points.end(); ++it) {
_vertex[i] = it->x()+2;
_vertex[i+1] = it->y()+2;
i+=2;
_colors[j] = getRed(j/4.0f, it);
_colors[j+1] = getGreen(j/4.0f, it);
_colors[j+2] = getBlue(j/4.0f, it);
_colors[j+3] = getAlpha(j/4.0f, it);
j+=4;
}
glColorPointer(4, GL_FLOAT, 0, _colors);
glVertexPointer(2, GL_FLOAT, 0, _vertex);
glDrawArrays(GL_LINE_STRIP, 0, points.size());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
delete _vertex;
delete _colors;
Is there a more efficent way for creating the arrays to pass to the graphic cards? like pass points.begin() and find out what is the offset and avoid to loop through all the points?
I mean.. in the memory the x and y coordinates of the Eigen::Vector2d has to be stored in some consecutive space.. so.. I think I can pass it directly to the graphic card.. but I can't unserstand how.
std::list does not hold it's data in contiguous memory, you need std::vector for that(or std::array if you know the size at compile time, but you probably don't). Vector has a method data() which returns a pointer to underlying data. However if you store internally Eigen::vec2d you can't pass it to openGl, since it's a dynamic structure and your data will be all over your memory. You need structure that keeps data in place(and btw is more readable than vec2d, which is kinda odd in this context). For example:
struct VertexData
{
GLfloat x;
GLfloat y;
GLfloat red;
GLfloat green;
GLfloat blue;
GLfloat alpha;
}
And then use glVertexPointer to pass it to openGL using sizeof(VertexData) as stride
To delete new'ed arrays you need to use
delete [] _vertex;
normal delete will only free the first element. Or even better, you could use smart pointers, std::unique_ptr would be best in this case
std::unique_ptr<GLfloat[]> _vertex(new GLfloat[points.size() * sizeof(GLfloat)]);
It will automatically free the memory when it goes out of scope(at the end of the block)
points is a std::list so it doesn't contain an contiguous array of data.
If you use std::vector instead however, then in C++11 you can access the array used internally with points.data(). This means you don't need _vertex anymore.
Know that, as an alternative, you can even go further and have a class (named for instance Vertex) which contains both the vertex position and its color and then use the data() method on your std::vector<Vertex> in combination with glInterleavedArrays (with stride=sizeof(Vertex)).
I am generating the vertex arrays on the fly on each render and I want to delete the arrays afterwards. Does glDrawArrays immediately copy the vertex arrays to the server? Hence is it safe to delete the vertex arrays after calling glDrawArrays?
float * vp = GetVertices(); // Regenerated on each render
glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), vp);
glDrawArrays(GL_TRIANGLES, 0, nVertices);
delete[] vp; // Can I do this?
Otherwise, how can I determine when it is safe to delete the vertex arrays?
Yes, it is copied immediately, so once you've done the call you can do whatever you like with the array.
Also, as dirkgently pointed out, you need to use delete[] vp to delete an array.
Yes, you can delete the vertex array after calling glDrawArrays. But opengl won't store vertex data in it's memory. It will just use the vertex array and draws on the frame buffer. So next time if you want draw the same vertex, then you have to provide the vertex array again to glDrawArrays.