How to set up rendering in Metal

3 days ago 6
ARTICLE AD BOX

I am learning Metal. My starter project is a rewrite of an old Mac kaleidoscope app I wrote in Objective C and OpenGL. I'm rewriting it as a Multiplatform app in SwiftUI and Metal, using `MTKView`s.

The bulk of the drawing is fairly simple: I convert a source image to a texture, and then take a triangular section of that texture and tesselate it using various templates into my output. The program animates moving the source triangle around in the texture and generating moving kaleidoscopic images.

I have a second view that shows the source image with an outline showing the current triangular bit that is being used. I also outline the corner points to indicate that the user can drag them to resize the triangle, and draw a circle in the source image that indicates the center point it uses to move and rotate the sample triangle around in the source image.

Right now I have a single command queue for each MTKView. I reuse my render pass descriptor, and create a single command encoder for each frame, using the same vertex and fragment shader for all drawing. I've added various parameters to the Uniforms that I pass to my shader that let me draw with my texture, or with solid colors. At this point I have a "kitchen sink" Uninforms object that I pass to my shaders where some of the parameters are used for some drawing and others are used for other types of drawing. Given the overhead of passing data to the GPU, this is probably not the best way to do things.

The struct I pass to Metal looks like this right now:

struct Uniforms { let color: simd_float4 // Only used when drawing outlines let drawWithTetxure: Bool // Tells shader to draw w texture vs color let drawTextureTriangles: Bool let textureTriangle: TrianglePoints let texAspect: Float let orthoMatrix: float4x4 }

I hacked up a pretty bad graphic that shows the rotation point of my source triangle using individual line segments to create a circle and an arc with an arrowhead on it showing the direction of rotation. It looks like the below. (It is very much "programmer art" and in desperate need of improvement)

enter image description here

(And somehow half of my arrowhead has disappeared since last time I looked at it.)

I want to rewrite the code that draws my rotation point graphic to use triangle strips and a clean white lines with a black outline so it shows up clearly against light, dark, and visually busy images.

I have written a stand-alone single view app that draws very clean "Donuts" (circle outlines with a thickness.) I want to bring that into my main app.

I am wondering if I should set up different command encoders with different shaders for the different rendering passes rather than using one command encoder, one vertex shader, and one fragment shader to do everything.

I'm at the stage where figuring out how to do anything new is hard, and looking for advice and example projects to study.

Can somebody with more experience with Metal give me some suggestions?

Update

I fixed my code that draws arcs and circles to draw them using triangle strips rather than a series of adjoining line segments, and that solves the line join problems in my previous drawing. (I also fixed the bug that caused one of my arrowhead lines to be missing.) The new results look like this:

enter image description here

I'm still using my single render pass descriptor and command encoder for all drawing and passing in a fixed Uniforms struct to the shaders even though not all the parameters are used in every case.

I could still use some help understanding how you decide when it's better to create multiple shaders and command encoders.

Read Entire Article