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

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.

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.

### 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.

## Translation

The starter project renders two triangles:

## 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.

### 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;
``````

``````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
``````

``````matrix = translation * scaleMatrix
``````

## 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
``````

``````matrix = translation * rotationMatrix * scaleMatrix
``````

``````translation.columns.3.x = triangle.vertices[6]
translation.columns.3.y = triangle.vertices[7]
translation.columns.3.z = triangle.vertices[8]
``````
``````matrix = translation.inverse
``````

``````matrix = rotationMatrix * translation.inverse
``````

``````matrix = translation * rotationMatrix * translation.inverse
``````

## 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.