vendredi 27 février 2015

C++ interface for managing OpenGL vertex attributes

Four years ago I wrote a basic GLES2 engine in ObjC (http://ift.tt/1Djdo2B)


It struck me that certain operations are high in boilerplate, the best example being the loading of the vertex data to the GPU (specifically, creating a struct Vertex to match the vertex shader's attributes, and informing GL of the data packing).


I'm now working in C++11 using JUCE, which comes with a low-level GL wrapper API.


Attribute handling looks like this: http://ift.tt/1DjdmaZ


I hope that link makes it fairly obvious what I mean by "boilerplate heavy". If you wish to use the different shader, you must replicate a lot of lines of code; createAttribute, glVertexAttribPointer, glEnableVertexAttribArray, glDisableVertexAttribArray. And glVertexAttribPointer is particularly ugly, it requires the offset of the attribute within the vertex data structure.


So this is my question: how can I abstract out the specifics, to create a generic attribute handler? Using C++11 constructs it should be possible to automate much of the work.


I'm not going to ask for an implementation (although I would welcome any). I'm asking what a good interface would look like.


There are a lot of C++ GL engines out there, so I'm guessing this problem has been solved in a variety of different ways.




Here is my thinking so far:


glGetActiveAttrib looks like it allows one to extract the attributes from the shader source: 1, 2


So how about first compiling the shader, and then using glGetActiveAttrib to subsequently create a vertex structure?



class Vert {
void setupUsingShaderProgram(p) {
/* use glGetActiveAttrib on p... */
bytes = ...
}
int bytes;

void* operator [] (std::string nameInShader) {
// allow things like myvert['position']
// ... Supposing the shader contains:
// `attribute vec4 position;`
}


Problems:(1) type safety; having to typecast that void* into say a GLFloat[4]* the consumer could end up overwriting. (2) look up speed -- a dictionary lookup wouldn't be acceptable in a lot of situations like when you were manually setting values on thousands of vertices.


So I think the consumer would have to specify:



using Vert_xyz_uv_rgba = VertexGenerator< Vec3, Vec2, Vec4 >;

auto vert = Vert_xyz_uv_rgba(openGLContext, shaderprog);


And maybe Vert_xyz_uv_rgba contains a tuple containing a Vec3, Vec2, Vec4


So the consumer could do things like:



vert.setnumverts(1000);
vert[307][0] = someVec3;

//or...
vert[307]["position"] = someVec3; // again slow lookup


I can't see any nice solution. Ideally I would want to do something like:



using V = VertexGenerator< Vec3 position, Vec2 tex_uv, Vec4 rgba >;
auto vert = V(openGLContext, shaderprog);
vert[307].position = ...


So maybe I could create a C struct for a particular vertex type:



struct xyz_uv_rgba // CRTP? : VertGenerator<xyz_uv_rgba>
{
GLFloat xyz[3];
GLFloat uv[2];
GLFloat rgba[4];
}


That wouldn't be too much of a burden to create for each individual shader. Just mirror its attributes as a C-struct.


And it should be possible to automate the createAttribute, glVertexAttribPointer, glEnableVertexAttribArray, glDisableVertexAttribArray making use of glGetActiveAttrib.


Please don't be too hasty closing this question for being too open -- there will be a small number of viable patterns for doing this.


Aucun commentaire:

Enregistrer un commentaire