Issue #768 new

Custom vertex attributes for Meshes

Alex Szpakowski avatarAlex Szpakowski created an issue

Custom vertex attributes are something I feel would hugely benefit love.graphics' extensibility by lovers (keeping in line with the "mechanism over policy" philosophy), provided they aren't required knowledge for any simple uses of LÖVE.

For those who don't know, a vertex attribute is some variable associated with a vertex in an object. For example, all things drawn in LÖVE currently have some combination of position, color, and texture coordinate vertex attributes. Custom attributes would have a lover-defined number of components (between 1 and 4) per attribute, and would likely only be usable from inside a custom vertex shader, since LÖVE wouldn't have any use for the lover-defined attribute on its own.

I think the Mesh type is the best place to have them, since you already specify per-vertex attribute information.

The tricky part is coming up with an implementation that's as simple and as powerful as possible, while also not interfering with "standard" use of Meshes (no custom attributes.)

Unity3d and libgdx' Mesh objects both seem to have have several pre-defined attributes you can choose to use. libgdx' implementation looks a bit more customizable than Unity's.

This is pretty good, but maybe a bit brittle. We should see if we can do better.

One issue we will have to deal with is how to link the custom attributes to the attribute variables in vertex shaders. It could either be by string name or by index. There are some downsides to each, mostly relating to how OpenGL links them together in its own API.

Another is how to keep the out-facing API clean and simple. I like Mesh:setVertex(index, x, y, u, v, r, g, b, a) (etc.) but obviously it wouldn't work like that with custom attributes.

And, we should decide whether to have custom attributes as an "array of vertices" (as the current API is) or as individual arrays per attribute. The benefit to the former is it cleanly identifies each individual vertex and is also more performant normally. The benefit to the latter is the API might(?) be easier to figure out and it can give better performance if you only want to modify a single attribute of every vertex.

I don't consider this a blocker for 0.9.0, but it might be nice to squeeze it in before release. :)

Comments (3)

  1. Alex Szpakowski

    It's also worth noting that (aside from the obvious position attribute), per-vertex texture coordinate and color information is very useful even when shaders aren't used, so the API still needs to be able to use those without shaders - but it would also be really nice if the API let you choose the number of components for those attributes (e.g. xyz position, or 4-component texture coordinates.)

    For the truly custom attributes, choosing the type of data (normalized byte or float) would also be useful. OpenGL's pre-shader API doesn't let position and texture coordinates be normalized bytes.

  2. Alex Szpakowski

    This is what I've come up with so far. It's still a WIP and I'm not completely happy with the APIs though.


    There's a new object: VertexBuffer. It stores arrays of vertex attributes. It can either store a single attribute repeated N times, or a collection of attributes repeated N times.

    When you create a VertexBuffer, you give it the formats of the vertex attributes you want to store in the buffer. This is a table, and looks something like this: {"float",2, "byte",4}. That format table would mean the VertexBuffer has an array of 2-component floating point numbers plus 4-component byte numbers. That particular case could represent x,y, r,g,b,a, for example.

    You also give the VertexBuffer constructor one of these:

    • A number representing the total number of vertices to store in the buffer (a "vertex" in this case just means the collection of attributes defined above.)
    • Or a table containing tables with the vertex attribute values in them, matching the definition you gave. For the example above, {{0,0, 255,255,255,128}, {100,0, 255,0,255,255}, {100,100, 255,0,0,255}} would be valid and contains 3 vertices (3 sets of vertex attributes.)

    VertexBuffers can have their contents modified. either with VertexBuffer:setVertex(vertexindex, a1_1, a1_2, a2_1, a2_2, ...) or with VertexBuffer:setAttribute(vertexindex, attributeindex, a2, a2, ...). The former sets all the attributes for a particular vertex in the VertexBuffer, the latter sets a specific attribute in a specific vertex.

    You can attach an attribute from a VertexBuffer to a Mesh. When you do that, the attribute will be used when drawing the Mesh (provided you have a shader which makes use of the attribute.)

    The syntax for that is: Mesh:setVertexAttribute(attribname, vertexbuffer, attributeindex). For the example above, I might do: Mesh:setVertexAttribute("mycolor", buffer, 2), which would make the Mesh use the second attribute in my VertexBuffer (not the second vertex).

    When drawing a Mesh with attributes attached, a Vertex Shader needs to be active which makes use of those attributes. The shader's name for the attributes also needs to match the names given in setVertexAttribute. For the example above, the vertex shader should have attribute vec4 mycolor; declared near the top (and it should use it in its code.)

    A shader is needed because LÖVE wouldn't know what to do with the attribute otherwise. There are also some features of this which wouldn't work at all if I made this work without shaders.

    There is also an optional variant of Mesh:setVertexAttribute, where an additional number parameter specifies how many instances (via Mesh:setInstanceCount) should be drawn before the next attribute of the buffer is used. If it's 0, the attribute is per-vertex, otherwise it's used per-instance or per-10-instances or whatever you want.

  3. Log in to comment
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.