how to split values from coordinates in OpenGL vertex buffer objects - opengl

For drawing a heatmap in OpenGL we want to give each point x,y, and value.
We could just store a vbo with these values and split it into two vertexattrib pointers:
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)sizeof(float));
However, when updating the values this would require writing only to the value between the xy points that are not changing. Is there a way to specify a separate array for the values so that each vertexattrib pointer comes from a different source?
#genpfault is suggesting a solution like this:
glBind(vboPoints);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBind(vboVals);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, (void*)0);
If this is correct, is there a limit to the number of different vbos that can be used in this way?
Is this slower than using a single block of memory with all values interleaved?

Is there a way to specify a separate array for the values so that each vertexattrib pointer comes from a different source?
Bind a different VBO before each glVertexAttribPointer() call. Don't forget to adjust the stride/offset appropriately.
There's no limit to the number of VBOs used this way other than the vertex attribute limit (query via glGet*() with GL_MAX_VERTEX_ATTRIBS)
The performance difference vs. interleaved data will be implementation-dependent: there's no way to query what (if any) caching a GL implementation is doing internally on buffer accesses. For all anyone knows it could re-interleave the data streams internally.
Best you can really do is give the driver usage hints via the usage parameter to glBufferData():
usage is a hint to the GL implementation as to how a buffer object's data store will be accessed. This enables the GL implementation to make more intelligent decisions that may significantly impact buffer object performance. It does not, however, constrain the actual usage of the data store.
So for your example the vboPoints buffer could be GL_STATIC_DRAW while the vboVals might be better off as GL_DYNAMIC_DRAW.

Related

Why do I need to specify data for both the VBO and while calling glVertexAttribPointer?

When using OpenGl I usually create a VBO and pass the vertex data to it with
glBufferData();
I have been reading this source recently, and please let me cite one part of it:
While creating the new storage, any pre-existing data store is deleted. The new data store is created with the specified size in bytes and usage. If data is not NULL, the data store is initialized with data from this pointer. In its initial state, the new data store is not mapped, it has a NULL mapped pointer, and its mapped access is GL_READ_WRITE.
From this I conclude, that while buffer data function is set, the data from the buffer is copied to the VBO.
Now, when calling glVertexAttribPointer() I have to pass a pointer to the data again.
I understand the purpose of attrib pointers - they tell the OpenGL state machine how the data is organised in the VBO.
However, passing the pointer both to VBO and then to the glVertexAttribPointer function seems redundant, since the VAO saves the attrib pointer configuration anyway, and to call glVertexAttribPointer one has to store the vertex data in the program memory anyway - so the memory gets duplicated (one primal copy and the copy made by glBufferData()).
Why is this apparent redundancy present? Or maybe I understand something the wrong way?
Maybe I misunderstood the documentation and the data is not copied to VBO, but what would be the purpose of VBOs anyway then?
You don't have to. If a named buffer object is bound to the ARRAY_BUFFER target then the last argument (pointer) of glVertexAttribPointer is treated as a byte offset into the buffer object's data store.
Either (only compatibility profile):
float *data;
glBindBuffer(GL_ARRAY_BUFFER, 0); // 0 is default
glVertexAttribPointer(..., data);
or
float *data;
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, ..., data, ...);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(..., (void*)0);

Portable way to create heterogenous vertex data array

It is very common in graphics programming to work with vertex formats.
This is described, for example, here.
However, I am looking for a way to accomplish that which does not invoke undefined behavior
(I'm mainly looking for C++ info, but C would be fine, too).
The common way to do it is like this: First, declare your vertex format as a struct.
struct Vertex {
float x;
float y;
uint16_t someData;
float etc;
};
Then, you create an array of these, fill them in, and send them to your graphics API (eg: OpenGL).
Vertex myVerts[100];
myVerts[0].x = 42.0;
// etc.
// when done, send the data along:
graphicsApi_CreateVertexBuffer(&myVerts[0], ...);
(Aside: I skipped the part where you tell the API what the format is; we'll just assume it knows).
However, the graphics API has no knowledge about your struct. It just wants a sequence of values in memory, something like:
|<--- first vertex -->||<--- second vertex -->| ...
[float][float][u16][float][float][float][u16][float] ...
And thanks to issues of packing and alignment, there is no guarantee that myVerts will be laid out that way in memory.
Of course, tons of code is written this way, and it works, despite not being portable.
But is there any portable way to do this that is not either
1. Inefficient
2. Awkward to write
?
This is basically a serialization problem. See also: Correct, portable way to interpret buffer as a struct
The main standards-compliant way I know of is to allocate your memory as char[].
Then, you just fill in all the bytes exactly how you want them laid out.
But to transform from the struct Vertex representation above to that char[] representation would require an extra copy (and a slow byte-by-byte one, at that). So that's inefficient.
Alternatively, you could write data into the char[] representation directly, but that's extremely awkward. It's much nicer to say verts[5].x = 3.0f than addressing into a byte array, writing a float as 4 bytes, etc.
Is there a good, portable way to do this?
However, the graphics API has no knowledge about your struct. It just wants a sequence of values in memory, something like:
|<--- first vertex -->||<--- second vertex -->| ...
[float][float][u16][float][float][float][u16][float] ...
This is not true. The graphics API has knowledge about your struct, because you told it about your struct. You even know this already:
(Aside: I skipped the part where you tell the API what the format is; we'll just assume it knows).
When you tell the graphics API where each field is in your struct, you should use sizeof and offsetof instead of guessing the layout of your struct. Then your code will work even if the compiler inserts padding. For example (in OpenGL):
struct Vertex {
float position[2];
uint16_t someData;
float etc;
};
glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE, sizeof(struct Vertex), (void*)offsetof(struct Vertex, position));
glVertexAttribIPointer(someData_index, 1, GL_SHORT, sizeof(struct Vertex), (void*)offsetof(struct Vertex, someData));
glVertexAttribPointer(etc_index, 1, GL_FLOAT, GL_FALSE, sizeof(struct Vertex), (void*)offsetof(struct Vertex, etc));
not
glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE, 14, (void*)0);
glVertexAttribIPointer(someData_index, 1, GL_SHORT, 14, (void*)8);
glVertexAttribPointer(etc_index, 1, GL_FLOAT, GL_FALSE, 14, (void*)10);
Of course, if you were reading your vertices from disk as a blob of bytes in a known format (which could be different from the compiler's struct layout), then you may use a hardcoded layout to interpret those bytes. If you're treating vertices as an array of structs, then use the layout the compiler has decided for you.

OpenGL stride glVertexPointer

I am working on a OpenGL 2.0 renderer (https://bitbucket.org/mattiascibien/anima-render) and I actually came across smething I cannot understand at all which is the stride for the glVertexPointer() instruction. Actually my code looks like this
glBindBuffer(GL_ARRAY_BUFFER, data.vertex_buffer);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(
3,
GL_FLOAT,
sizeof(GLfloat)*3,
(void*)0
);
but I actually found that by reading OpenGL documentation the stride should actually be 0. Changing it does not change how the model is rendered.
What value is correct? Why does changing this parameter makes no difference?
EDIT: the data is stored in a
std::vector<GLFloat>
same happens with glTexCoordPointer using sizeof(GLfloat)*2 or 0
https://www.opengl.org/sdk/docs/man2/xhtml/glInterleavedArrays.xml gives more infos about it.
If stride is 0, the aggregate elements are stored consecutively. Otherwise, stride bytes occur between the beginning of one aggregate array element and the beginning of the next aggregate array element.
while you are providing a stride, that is 0 or your "struct" size (3*sizeof(GLFloat)) this is the same. Yet I'd go with 0 in this case.
Stride is the distance from the beginning of one entity, to the beginning of the following entity. 0 is special: it means the distance from the end of one entity to the beginning of the next entity is 0. So basically 0 is the same as sizeof(entity).
Basically they packed 2 different mechanisms in one parameter, which I find suboptimal.

glbufferdata with Vector of pointers c++

In c++ and openGL4 I can do something like this
std::vector<Vertex> vertices;
Where Vertex is a class that holds the relevant per vertex data.
this->vertices.pushback(Vertex())
....define the rest of the vertices and set position and color data etc
//Opengl code
glBindBuffer(GL_ARRAY_BUFFER, this->vboID[0]);
glBufferData(GL_ARRAY_BUFFER, ( this->vertices.size() * sizeof(Vertex) ) , this->vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer((GLuint)0, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid *)0); // Set up our vertex attributes pointer
glEnableVertexAttribArray(0);
This works fine and displays what I am rendering fine. Now if I try to make the vector
std::vector<Vertex*> vertices;
this->vertices.push_back(new Vertex());
....
then the shape I want to display never shows up.
My question is this because I use pointers that the data is no longer continuous and so opengl can't read the vertex data or is it possible to alter the openGL code to accept the vector of pointers?
Well, of course. In the first version, you are passing the actual Vertex instances to OpenGL as a byte buffer. In the second version, you are passing pointers to the Vertex instances to OpenGL, and OpenGL won't dereference these pointers for you.
You need to use the first version, there is no way to pass pointers to your Vertices to OpenGL.
OpenGL needs the raw vertex data. It has no conception of how that data is formatted when it is being buffered. It's a dumb buffer. It is not possible for OpenGL to accept the vector of pointers - even if it did, it would still have to extract the vertices and put them into a contiguous array for optimal layout and sending to the graphics hardware.
What you're doing is sending a bunch of raw data to the graphics hardware that will be interpreted as vertices per glVertexAttribPointer. Imagine it is doing a reinterpret_cast behinds the scenes - it is now interpreting some (say, 32-bit integral) pointers as though they were supposed to be sets of 4, 32-bit, floating point values.
I suspect you opted to make a vector of vertex pointers rather than an array of vertices because of the overhead when inserting into the vector? You should pre-size your vector with a call to reserve or resize, whichever is more appropriate so as to pay the reallocation costs once only.
Do not use std::vector <...>::data (...) if you care about portability. That does not exist in older versions of C++. Beginning with C++03, &std::vector <...> [0] is guaranteed to return the address of a contiguous block of data representing the first element stored in the vector. It worked this way long before that, but this was the first time the behavior was absolutely guaranteed.
But your fundamental problem here is that GL is not going to dereference the pointers you stored in your vector when it comes time to get data. That is what your vector stores, after all. You need the vector to store actual data, and not a list of pointers to data.

OpenGL Vertex buffer object, can I access the vertex data for other uses such as collision detection?

I'm currently using the GLTools classes that come along with the Superbible 5th edition. I'm looking in the GLTriangleBatch class and it has the following code:
// Create the master vertex array object
glGenVertexArrays(1, &vertexArrayBufferObject);
glBindVertexArray(vertexArrayBufferObject);
// Create the buffer objects
glGenBuffers(4, bufferObjects);
#define VERTEX_DATA 0
#define NORMAL_DATA 1
#define TEXTURE_DATA 2
#define INDEX_DATA 3
// Copy data to video memory
// Vertex data
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[VERTEX_DATA]);
glEnableVertexAttribArray(GLT_ATTRIBUTE_VERTEX);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*3, pVerts, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_VERTEX, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Normal data
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[NORMAL_DATA]);
glEnableVertexAttribArray(GLT_ATTRIBUTE_NORMAL);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*3, pNorms, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_NORMAL, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Texture coordinates
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[TEXTURE_DATA]);
glEnableVertexAttribArray(GLT_ATTRIBUTE_TEXTURE0);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*nNumVerts*2, pTexCoords, GL_STATIC_DRAW);
glVertexAttribPointer(GLT_ATTRIBUTE_TEXTURE0, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Indexes
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects[INDEX_DATA]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort)*nNumIndexes, pIndexes, GL_STATIC_DRAW);
// Done
glBindVertexArray(0);
// Free older, larger arrays
delete [] pIndexes;
delete [] pVerts;
delete [] pNorms;
delete [] pTexCoords;
// Reasign pointers so they are marked as unused
pIndexes = NULL;
pVerts = NULL;
pNorms = NULL;
pTexCoords = NULL;
From what I understand the code passes the arrays that the pointers pVerts, pNorms, pTexCoords, pIndexes and stores them in a Vertex array object, which essentially is an array of vertex buffer objects. These are stored in memory on the GPU. The original pointers are then deleted.
I'm interested in accessing the vertex positions, which were held in the array pVert pointed to.
Now my question revolves around collision detection. I want to be able to access an array of all of the vertices of my GLTriangleBatch. Can I obtain them through the vertexBufferObject at a later time using some sort of getter method? Would it be best to just keep the pVerts pointer around and use a getter method for that instead? I'm thinking in terms of performance, as I hope to implement a GJK collision detection algorithm in the future...
Buffer objects, when used as sources for vertex data, exist for the benefit of rendering. Going backwards (reading the data back) is generally not advisable from a performance point of view.
The hint you give glBufferData has three access patterns: DRAW, READ, and COPY; these tell OpenGL how you intend to be getting/retrieving data from the buffer object directly. The hints do not govern how OpenGL should be reading/writing from/to it. These are just hints; the API doesn't enforce any particular behavior, but violating them may lead to poor performance.
DRAW means that you will put data into the buffer, but you will not read from it. READ means that you will read data from the buffer, but you will not write to it (typically for transform feedback or pixel buffers). And COPY means that you will neither read from nor write to the buffer directly.
Notice that there is no hint for "read and write." There is just "write", "read", and "neither." Consider that a hint as to how good of an idea it is to write data to a buffer directly and then start reading from that buffer.
Again, the hints are for the user directly getting or retrieving data. glBufferData, glBufferSubData, and the various mapping functions all do writes, while glGetBufferSubData and mapping functions all do reads.
In any case no, you should not do this. Keep a copy of the position data around in client memory if you need to use it on the client.
Also, some drivers ignore the usage hints entirely. They instead decide where to place the buffer object based on how you actually use it, rather than how you say you intend to use it. This will be worse for you, because if you start reading from that buffer, the driver may move the buffer's data to memory that is not as fast. It may be moved out of the GPU and even into the client memory space.
However, if you insist on doing this, there are two ways to read data from a buffer object. glGetBufferSubData is the inverse of glBufferSubData. And you can always map the buffer for reading instead of writing.