Rendering a Triangle (Metal Part 2)

z4gon
z4gon

Rendering a primitive triangle using the GPU, a vertices array, and a memory buffer. Writing a vertex function to access the individual vertices and passing them down to the fragment stage shader.

Cover Image for Rendering a Triangle (Metal Part 2)

Source Code

See Project in GitHub 👩‍💻

References


Table of Content


Vertex Buffer

Rendering Primitives MTL Buffer

Define an array of vectors representing the vertices we want to draw in the screen.

1// counter clock wise to define the face 2var vertices: [float3] = [ 3 float3(0, 1, 0), // top mid 4 float3(-1, -1, 0), // bot left 5 float3(1, -1, 0), // top right 6]

Declare the memory buffer which will be used to hold the vertices information in the GPU.

1var vertexBuffer: MTLBuffer!;

Initialize the buffer by creating it off of the device reference.

The content is going to be the vertices array, the total memory amount is going to be the stride of an individual vertex times the amount of vertices.

1func createBuffers() { 2 let vertexMemSize = MemoryLayout<float3>.stride 3 4 vertexBuffer = device?.makeBuffer(bytes: vertices, length: vertexMemSize * vertices.count, options: []) 5}

Vertex Shader

Using attributes for arguments Metal-Shading-Language-Specification

We need to lookup vertex data in the buffer manually, by using the attribute [[buffer(0)]].

The attribute [[vertex_id]] allows us to get the vertex index in the buffer.

1vertex float4 basic_vertex_shader( 2 device float3 *vertices [[ buffer(0) ]], // access the vertices buffer at buffer with index 0 3 uint vertexID [[ vertex_id ]] // get the vertex id, which corresponds to the index of the vertex in the buffer 4){ 5 return float4(vertices[vertexID], 1); // return the vertex position in homogeneous screen space 6}

Draw Primitives

MTL PrimitiveType

We set the buffer to the encoder, so that the GPU can use it when executing the vertex function.

Drawing the primitives needs a specific primitive type, where we start to consider vertices, and how many vertices we will draw.

1// send info to render command encoder 2renderCommandEncoder?.setVertexBuffer(vertexBuffer, offset: 0, index: 0) 3// draw a triangle using the vertices in the buffer 4renderCommandEncoder?.drawPrimitives(type: MTLPrimitiveType.triangle, vertexStart: 0, vertexCount: vertices.count)

Result

Picture