Chapters

Hide chapters

Metal by Tutorials

Third Edition · macOS 12 · iOS 15 · Swift 5.5 · Xcode 13

Section I: Beginning Metal

Section 1: 10 chapters
Show chapters Hide chapters

Section II: Intermediate Metal

Section 2: 8 chapters
Show chapters Hide chapters

Section III: Advanced Metal

Section 3: 8 chapters
Show chapters Hide chapters

5. 3D Transformations
Written by Marius Horga & Caroline Begbie

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

In the previous chapter, you translated vertices and moved objects around the screen by calculating the position data in the vertex function. But there’s a lot more you’ll want to do when working in 3D space, such as rotating and scaling your objects. You’ll also want to have an in-scene camera so that you can move around your scene.

To move, scale and rotate a triangle, you’ll use matrices — and once you’ve mastered one triangle, it’s a cinch to rotate a model with thousands of triangles at once!

For those of us who aren’t math geniuses, vectors and matrices can be a bit scary. Fortunately, you don’t always have to know what’s under the hood when using math. To help, this chapter focuses not on the math, but the matrices. As you work through this chapter, you’ll gradually extend your linear algebra knowledge as you learn what matrices can do for you and how to manipulate them.

Transformations

Look at the following picture.

Affine Transformations
Affine Transformations

Using the vector image editor, Affinity Designer, you can scale and rotate a cat through a series of affine transformations. Instead of individually calculating each position, Affinity Designer creates a transformation matrix that holds the combination of the transformations. It then applies the transformation to each element.

Note: Affine means that after you’ve done the transformation, all parallel lines remain parallel.

Of course, no one wants to translate, scale and rotate a cat since they’ll probably bite. So instead, you’ll translate, scale and rotate a triangle.

The Starter Project & Setup

➤ Open and run the starter project located in the starter folder for this chapter.

The starter project
Cci mfehhiz jyovikj

Setting Up the Preview Using SwiftUI

When making small tweaks, you can preview your changes using SwiftUI rather than running the project each time. You’ll pin the preview so that no matter what file you open, the preview remains visible.

Showing the preview canvas
Zfayazt swu kmedeay fajden

The preview
Jme zzimeef

Pinning the preview
Benxuxz gcu jveluim

Translation

The starter project renders two triangles:

Displacement Vectors
Remyqayidets Qeqmusp

Vectors & Matrices

You can better describe position as a displacement vector of [0.3, -0.4, 0]. You move each vertex 0.3 units in the x-direction, and -0.4 in the y-direction from its starting position.

Vectors
Luzbisx

An identity matrix
Ir uraybebv nakvag

The Magic of Matrices

When you multiply matrices, you combine them into one matrix. You can then multiply a vector by this matrix to transform the vector. For example, you can set up a rotation matrix and a translation matrix. You can then calculate the transformed position with the following line of code:

translationMatrix * rotationMatrix * positionVector

Creating a Matrix

➤ Open Renderer.swift, and locate where you render the first gray triangle in draw(in:).

var position = simd_float3(0, 0, 0)
renderEncoder.setVertexBytes(
  &position,
  length: MemoryLayout<SIMD3<Float>>.stride,
  index: 11)
var translation = matrix_float4x4()
translation.columns.0 = [1, 0, 0, 0]
translation.columns.1 = [0, 1, 0, 0]
translation.columns.2 = [0, 0, 1, 0]
translation.columns.3 = [0, 0, 0, 1]
var matrix = translation
renderEncoder.setVertexBytes(
  &matrix,
  length: MemoryLayout<matrix_float4x4>.stride,
  index: 11)
position = simd_float3(0.3, -0.4, 0)
renderEncoder.setVertexBytes(
  &position,
  length: MemoryLayout<SIMD3<Float>>.stride,
  index: 11)
let position = simd_float3(0.3, -0.4, 0)
translation.columns.3.x = position.x
translation.columns.3.y = position.y
translation.columns.3.z = position.z
matrix = translation
renderEncoder.setVertexBytes(
  &matrix,
  length: MemoryLayout<matrix_float4x4>.stride,
  index: 11)
constant float3 &position [[buffer(11)]])
constant float4x4 &matrix [[buffer(11)]])
float3 translation = in.position.xyz + position;
float3 translation = in.position.xyz + matrix.columns[3].xyz;
Translation by adding a matrix column to the position
Rvohxgadaif kp aglomk a dolkat xovimf vi pwo qelexoex

float4 translation = matrix * in.position;
VertexOut out {
  .position = translation
};
return out;

Scaling

➤ Open Renderer.swift, and in draw(in:), locate where you set matrix in the second red triangle.

let scaleX: Float = 1.2
let scaleY: Float = 0.5
let scaleMatrix = float4x4(
  [scaleX, 0,   0,   0],
  [0, scaleY,   0,   0],
  [0,      0,   1,   0],
  [0,      0,   0,   1])
matrix = scaleMatrix
Scaling with a matrix
Dnaditc zugv e dopbog

matrix = translation * scaleMatrix
A translated and scaled triangle
E hdigqvodut adn dmegen mxaacbnu

Rotation

You perform rotation in a similar way to scaling.

let angle = Float.pi / 2.0
let rotationMatrix = float4x4(
  [cos(angle), -sin(angle), 0,    0],
  [sin(angle),  cos(angle), 0,    0],
  [0,           0,          1,    0],
  [0,           0,          0,    1])

matrix = rotationMatrix
Rotating about the origin
Retacotq icuun myu udojal

matrix = translation * rotationMatrix * scaleMatrix
Scale, rotate and translate
Bnute, samaho udh rcumjxufa

translation.columns.3.x = triangle.vertices[6]
translation.columns.3.y = triangle.vertices[7]
translation.columns.3.z = triangle.vertices[8]
matrix = translation.inverse
Rotate about a point (1)
Divusi omoil o pauhr (8)

matrix = rotationMatrix * translation.inverse
Rotate about a point (2)
Fixoco ijiah u paibg (5)

matrix = translation * rotationMatrix * translation.inverse
Rotate about a point (3)
Yefaze ifeik a jiify (9)

Key Points

  • A vector is a matrix with only one row or column.
  • By combining three matrices for translation, rotation and scale, you can position a model anywhere in the scene.
  • In the resources folder for this chapter, references.markdown suggests further reading to help better understand transformations with linear algebra.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now