Vertex Descriptors (Metal Part 4)

z4gon
z4gon

Describing the memory layout for the vertices in the vertex buffer, so the vertex shader can pick them up individually.

Source Code

See Project in GitHub 👩‍💻

References


Table of Content


Vertex Descriptor

Create a MTL Vertex Descriptor and start defining the attributes.

This will allow the shader to just grab the individual vertex off of the vertex buffer, without needing to access the whole vertices array and extracting the vertex with the vertex id.

1// set the vertex descriptor 2let vertexDescriptor = MTLVertexDescriptor() 3 4// position 5// - first attribute, metal will use the attributes tags like so [[ attribute(0) ]] 6// - buffer index means the vertices are in the [[ buffer(0) ]] in metal 7// - no offset inside the struct, it's just the first attribute 8vertexDescriptor.attributes[0].format = MTLVertexFormat.float3 9vertexDescriptor.attributes[0].bufferIndex = 0 10vertexDescriptor.attributes[0].offset = 0 11 12// color 13// - second attribute, metal will use the attributes tags like so [[ attribute(1) ]] 14// - buffer index means the vertices are in the [[ buffer(0) ]] in metal 15// - offset inside the struct, needs to be the amount of memory of the position, in bytes 16vertexDescriptor.attributes[1].format = MTLVertexFormat.float4 17vertexDescriptor.attributes[1].bufferIndex = 0 18vertexDescriptor.attributes[1].offset = float3.size() 19 20// layout, how the pipeline state describes the struct 21// https://swiftunboxed.com/internals/size-stride-alignment/ 22vertexDescriptor.layouts[0].stride = Vertex.stride() 23 24renderPipelineDescriptor.vertexDescriptor = vertexDescriptor

Size vs Stride

The Stride will always be greater than or equal to the size.

It can be greater sometimes to favor memory alignment.

Picture

Image Source 🔗


Vertex Shader

The struct for the Vertex Data now needs to describe the attributes using the indexes that correspond to the vertex descriptor attributes, with [[ attribute(n) ]].

1struct VertexData { 2 float3 position [[ attribute(0) ]]; 3 float4 color [[ attribute(1) ]]; 4};

The Vertex Shader can now just take in the corresponding Vertex Data struct using [[ stage_in ]], because the GPU now has a description of the elements.

1vertex FragmentData basic_vertex_shader( 2 // metal can infer the data because we are describing it using the vertex descriptor 3 const VertexData IN [[ stage_in ]] 4){ 5 FragmentData OUT; 6 7 // return the vertex position in homogeneous screen space 8 OUT.position = float4(IN.position, 1); 9 OUT.color = IN.color; 10 11 return OUT; 12}

Result

The end result hasn't changed.

Picture