0
votes

I'm working on a 2d drawing app. I'd like to make an effect where lines expand, like this:

Expanded lines

This is for an animation where the lines expand and pop like balloons.

The lines are drawn as triangle strips. My idea is to make them expand by making each triangle larger in the vertex shader. Each vertex should be pushed away from the other vertices in the triangle.

To do this, I'd need to access the other vertices in the triangle. Is that possible in Metal?

vertex Vertex vertex_expand(device float2 *vertices [[buffer(0)]],
                          constant VertexUniforms *uniforms [[buffer(1)]],
                          uint vid [[vertex_id]]) {

// is vertices[vid - 1] and vertices[vid + 1] the previous and next vertices? 
// is vid=0 the first vertex?

}
2

2 Answers

1
votes

Yes, you can potentially access the other vertices, depending on how you do the draw. If you do indexed drawing then the relationship between vertex IDs and triangles is governed by your index buffer. The problem, though, is that you don't know the index being used for a given invocation of the vertex shader (and it might be invoked once for multiple indexes if those indexes all refer to the same vertex).

So, you would have to avoid indexed drawing.

In that case, yes, vertices[vid - 1] and vertices[vid + 1] are the previous and next vertices.

However, note that with a triangle strip, each vertex is a member of multiple triangles. So, there's not one unique triangle for each vertex away from whose center you can move that vertex to expand it. I expect you'd want the two vertexes that are neighbors along the same edge of the strip as the one you're processing, use those to compute a normal for the segment containing the current vertex, and move the vertex along that.

Since you're animating and thus going to be doing this repeatedly, you might want to compute those normals once in advance and pass them in as per-vertex data. You could use a compute shader for this computation, although doing it on the CPU may be fast enough. If you precompute the normals this way, the vertex shader won't need to reference any neighboring vertexes.

1
votes

Answering this because I don't have enough reputation to post a comment to Ken's answer. There seems to be a way to access the data of neighboring vertices during indexed drawing as well. Pass the index buffer as an argument to the vertex shader.

[encoder setVertexBuffer:vertices offset:0 atIndex:0 ];
[encoder setVertexBuffer:indices offset:0 atIndex:1];
[encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:indexCount];// this calls vertex shader with vid ranging from 0 to indexCount-1


vertex Vertex vertex_expand(device float2 *vertices [[buffer(0)]],
                            device uint *indices [[buffer(1)]],
                            uint vid [[vertex_id]]) {

// if vid % 3 == 0 then vertices[indices[vid]] is the current vertex and  vertices[indices[vid + 1]] and vertices[indices[vid + 2]] are the other two vertices belonging to the same triangle.

}