# Using MetalKit part 9

I bet many of you missed the `MetalKit`

series, so today we are returning back to it, and we will learn how to draw 3D content in `Metal`

. Let’s continue working on our playground and pick up where we left off in part 8 of the series.

We will render a 3D cube by the end of this episode but first let’s draw a 2D square and then we can re-use the square logic for all the other faces of the cube. Let’s modify the `vertex_data`

array so that it holds **4** vertices instead of **3** we needed for a triangle:

Here comes the interesting part. Since squares and any other complex geometry is made from triangles, and since most vertices belong to **2** or more triangles, there is no need to create copies of these vertices because we have a way of reusing them via an `index buffer`

that keeps track of the order in which the vertices will be used by storing each vertex index from the `vertex buffer`

. So let’s create such a list of indexes:

To understand how these indexes are stored, let’s look at this image below:

So for the front face (square) we use vertices stored at positions **0** through **3** in the `vertex_buffer`

. Later on we will add the other **4** vertices as well. The front face is made of two triangles. We first draw the triangle that uses vertices **0**, **1** and **2** and then we draw the triangle that uses vertices **2**, **3** and **0**. Notice that two of the vertices are re-used, as expected. Also notice the drawing is done **clockwise**. This is the default front-facing winding order in `Metal`

but it can be changed to `counterclockwise`

as well.

Then, we need to create the **index_buffer**:

Next, we need to assign the `index_data`

to the `index buffer`

inside the `createBuffers()`

function:

Last, inside the `drawRect(:)`

function we need to replace the `drawPrimitives`

call:

with a **drawIndexedPrimitives** call:

In the main playground page, see the generated new image:

Now that we know how to draw a square, let’s see how to draw more squares!

Now that we have the entire cube geometry ready for rendering, let’s go to `MathUtils.swift`

and in `modelMatrix()`

comment out the `rotation`

and the `translation`

calls, and only leave the scaling on for a factor of **0.5**. You will most likely see an image like this:

Hmm, but it’s still a square! Yes, it is, because we still don’t have the notion of `depth`

and the cube looks just flat. It’s time to tweak some math logic now. We don’t need to use the `Matrix`

struct anymore because the **simd** framework offers us similar data structures and math functions we can readily use. We can easily rewrite our transform functions to work with **matrix_float4x4** instead of the custom `Matrix`

struct we used.

But how do 3D objects end up on our 2D screens, you might ask. This process takes each pixel through a series of transformations. First the **modelMatrix()** transforms the pixel from `object space`

to `world space`

. This matrix is the one we already know, the one responsible for translations, rotations and scaling. With the newly rewritten functions above, the `modelMatrix`

could look like this:

You notice the useful `matrix_multiply`

function which we could not use before for the `Matrix`

struct. Also, since all these pixels will undergo the same transformation, we want to store the matrix as a **Uniform** and pass it to the `vertex shader`

. For this. let’s create a new struct:

Back in the `createBuffers()`

function, let’s pass the Uniforms to the shader via the buffer pointer we already used to pass the `modelMatrix`

:

In the main playground page, see the generated new image:

Hmm… the cube almost looks right, but something is still missing. The next transformation the pixels need to go through is from `world space`

to `camera space`

. Everything we see on the screen is *viewed* by a virtual camera through a **frustum** (pyramidal shape) that has a **near** and **far** planes to limit the view (camera) space:

Back in `MathUtils.swift`

let’s create the **viewMatrix()** as well:

The next transformation the pixels need to go through is from `camera space`

to `clip space`

. Here, all the vertices that are not inside the `clip space`

will determine whether the triangle will be `culled`

(all vertices outside the clip space) or `clipped to bounds`

(some vertices are outside but not all). The **projectionMatrix()** will help us compute the bounds and determine where the vertices are:

The last two transformations are from `clip space`

to `normalized device coordinates (NDC)`

and from `NDC`

to `screen space`

. These two transformations are handled by the Metal framework for us.

Next, back in the `createBuffers()`

function, let’s modify the `modelViewProjectionMatrix`

we set before to just the `modelMatrix`

:

In `drawRect(:)`

we need to set rules for the culling mode and for front facing, in order to avoid weird artifacts such as cube transparency:

In the main playground page, see the generated new image:

This is finally the 3D cube we were all waiting to see! There is one more thing we can do to make it even more realistic and lively looking: give it a spin. First, let’s create a global variable named **rotation** which we want to update as time goes by:

Next, grab all the matrices from inside the `createBuffers()`

function and let’s create a new one named **update()**. Here is where we update `rotation`

every frame to create a smooth rotation effect:

In `drawRect(:)`

call the `update`

function:

In the main playground page, you should see a similar image:

The source code is posted on Github as usual.

Until next time!