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