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)).
Related
I have a class which is supposed to keep pixel data (floats for the position, floats for the color). I'm trying to use a C++ style in data members (the data is kept in std::array<float, N> instead of plain C arrays). The class has other getters, setters and functions meant to be "helpers" to populate these fields.
Now I need to create an OpenGL vertex data buffer where I should write out
4 floats for xyzw
4 floats for rgba
2 floats for UV coords
in this order. I'm wondering how should I do this.. I tried doing
class MyVertexData {
std::array<float, 4> pos;
std::array<float, 4> rgba;
std::array<float, 2> uv;
public:
void writeData(float *ptrToMemory) {
if(ptrToMemory == nullptr)
throw std::runtime_exception("Null pointer");
std::array<float, 10> output;
output= {
pos[0], pos[1], pos[2], pos[3],
rgba[0], rgba[1], rgba[2], rgba[3],
uv[0], uv[1]
};
memcpy(memory, out.data(), 10 * sizeof(float));
}
};
// Caller code
std::vector<float[10]> buffer(4);
vertex0.writeElements(buffer[0]);
vertex1.writeElements(buffer[1]);
vertex2.writeElements(buffer[2]);
vertex3.writeElements(buffer[3]);
but this approach has two problems:
I need to trust the caller to have allocated memory to store 10 floats
No C++11+ signature, I just get a float pointer
I can't just return a std::unique_ptr since I need a contiguous memory area (buffer) where the elements are to be stored, but I also need a distinction between the different elements (that would also make the code more readable).
It would be nice to return a smart pointer or something similar whose memory I can easily "concatenate" to other elements so I can safely pass this stuff to OpenGL.
CppCoreGuidelines introduces span which is a view of contiguous element, so you may use something like:
void writeData(gsl::span<float, 10> ptrToMemory)
to express the intend.
What data GLSL takes? For example I have a matrix 4x4, which is following kind:
float **matrix = new float*[4];
for(int i = 0; i < 4; i++)
matrix[i] = new matrix[4];
Can the GLSL to take this, as mat4x4?
Or, better to use following:
float *matrix = new float[16];
I haven't found this information in specification of GLSL 1.30(I have use particularly this version)
First of all you should make use of GLfloat instead that float, since it's there exactly to represent GL data which is used by your program and the GPU.
Regarding your specific question glUniform has many flavours used to send what you need. You have both
void glUniformMatrix2f(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix4f(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
You can use them easily by passing the pointer to your data:
GLint location = glGetUniformLocation(variable,"variable_name");
glUniformMatrix4f(location, 1, false, &matrix);
You can't use the first variant, because the 16 floats of the matrix data will be allocated in different memory areas. You store array of 4 pointers, each pointing to separate 4xfloat array. OpenGL expects data to be located sequentially, so either use the second variant or use struct/static 2d array:
GLfloat[4][4]
It may be convenient to use the existing library for that, fore example gl matrix
What data GLSL takes? For example I have a matrix 4x4, which is following kind:
float **matrix = new float*[4];
for(int i = 0; i < 4; i++)
matrix[i] = new matrix[4];
That's not a 4×4 matrix. That's an array of pointers to arrays of 4 float elements.
Can the GLSL to take this, as mat4x4?
No, because it's not a matrix.
A 4×4 matrix would be a region of contiguous memory that contains 4·4 = 16 values (floats if you will) of which you denote, that each n-tuple (n=4) of values forms a vector and the m-tuple (m=4) of vectors forms a matrix.
Or, better to use following:
float *matrix = new float[16];
That would be a contiguous region of memory holding 16 = 4·4 float values, which by denotion can be interpreted as a 4×4 matrix of floats. So yes, this can be interpreted by OpenGL / GLSL as a 4×4 matrix of floats mat4.
However if you make this part of some class don't use dynamic memory.
class foo {
foo() { matrix = new float[16]; }
float *matrix;
};
Is bad, because you create some unnecessary overhead. If the class is dynamically allocated (with new) that will trigger another dynamic memory allocation, which creates overhead. If the instances are on automatic memory (stack, i.e. no new), it also imposes unnecessary overhead.
class foo {
foo() { … }
float matrix[16];
};
is much better, because if the class instances are created with new that also covers the memory for the matrix. And if it's on automatic memory it completely avoids the overhead of dynamic allocation.
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.
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 );
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.