Efficient way to draw a nice line using the Metal API

65 Views Asked by At

I want to draw straight lines that have a thickness and whose ends are half disks in Metal in an efficient manner. I think the natural way to do this is to render three quads (each is two triangles), one for the body of the line, to be colored in its entirety, the other two quads are the end points and will have a fragment shader check each fragment's uv-coordinates and determine whether it is inside the disk, i.e. essentially by checking x*x + y*y <= 1 (the uv-coordinates of these quads will be set to display the desired half disk).

My question is about the efficient use of Metal buffers and shaders. I do not have the disposal of OpenGL's geometry shader so I cannot take a line primitive and turn it into a given quads.

I have one hypothesis on what the best method might be. I can have first create the vertex data for a nice line in default position. Then, I can draw instances of this line, for each instance will rotate and extend and translate the line to the desired position on the screen. This can be formed into a single mat4 to multiply to each vertex per instance. However, I need to calculate each matrix for each line given pairs of points in the frame. I was thinking of using a compute pass to do so. But if lines are moving, I will run this compute pass each frame. Is this too expensive? or is this normal practice using Metal? I'm new to Metal so I want to find the best practice. Below is the pseudo-code for how the routine might be.

// === Data ===
MTLBuffer original_line  = < vertices for six triangles for a nice line with desired thickness >
MTLBuffer instances_data = < mat4 transform matrix per instance >
MTLBuffer line_data      = < each line has two float2 for end point positions in frame >

/* === Render Routine ===
- Run compute pass over line_data, recalculating each mat4 in instance_data;
- Run instanced render pass on original_line with instances_data for instance data;
*/

Lastly, there are two types of triangles for the fragment shader to consider, those which are filled in completely (body triangles) and those to check for disk fragments. We may do the entire instanced nice line in one draw call by setting the uv-coordinates of the body triangle to be all 0 so they pass the disk check. I have a suspicion that doing this opposed to having two draw calls for body triangles and end triangles might even improve performance. It's too simple of an operation to cause any significant stall at all.

0

There are 0 best solutions below