How to Draw in 3D With SwiftUI
By: Mark Lucking
Tags: Mobile, Swift, Programming, iOS, Swiftui

How to Draw in 3D With SwiftUI

Using native SwiftUI code to draw in 3D

In an article I published in April, I used the rotate tag in SwiftUI to rotate dominoes. The tag in question can be thought of as a convenient option. I say that because there is a more advanced one that gives you much more control.

The first two elements — the degrees of movement and the axis on which you want to turn the object — are exactly the same as with the convenient version. But in the advanced method, you have three other variables you can work with. As such, this tag is one of the most complex to use in the SwiftUI armory. Hopefully, this complexity will clear up as you read on.

Let’s start with the anchor. This basically determines which side you want to pivot on. The effect of the anchor is closely linked with the axis on which you are pivoting.

Rotating on the Z-axis around 360 degrees.

In the example above, I changed the degree of pivot around 360 degrees, initially doing so on the Z-axis. Here is the code behind the scenes (note that this gist is for the following piece):

You can clearly see the rotation3DEffect tag in code above, with the only variable I am animating being pivotDegree . Here is the code in action, making the green, blue, and purple boxes turn:

Rotating on the X-axis around 360 degrees.

Of course, there is the Y-axis on which you can also pivot. The next example shows just that:

Rotating on the Y-axis around 360 degrees.

Now I didn’t mention it, but we did use/set the perspective here too, setting it to 0.5. It controls the amount of swing. The higher the number, the greater the swing. Here is a GIF showing a perspective of 1.2 with some words of wisdom:

Rotation of each text object with perspective set to 4.

Note: It disappears as we swing through 90 degrees. We’ll use that later.

This brings us to the most challenging of the variables: the anchorZ . Set the code running the animation below to the values 10, 20, 30, 40, 50, 60, and 90. I chose those values because they correspond with the size of the rectangle I am moving about. The anchorZ controls the center point of the diameter on which you are pivoting around. You can see the effect most clearly with the red/pink square on the very end, which pulls to the back and then swings forward to the front.

Rotating on Z-anchor around 360 degrees.

In truth, I’ve been simplifying things just a little. You see, the anchor values I’m using are of a type UnitPoint . There are few presets, but you can mix and match your own combos to get some pretty cool effects:

@State var anchorPView: UnitPoint = UnitPoint(x: 0, y: 0)

Rotating on a custom axis around 360 degrees.

The values are a little odd since we’re rotating on the X-axis and varying the Y-value in the UnitPoint variable. A value of zero here is in effect a UnitPoint.top , and value of one is a UnitPoint.bottom . The other values are somewhere in between. In terms of degrees, we’re travelling 360, so a full circle. Note how similar it looks to the previous example. It is using perspective but only a value of 0.5. Our card at the end of this animation swings in front and then back in line.

Here is the code for a portion of this piece:

Be warned, things can get confusing because many of the attributes are interlinked. So if you’re not careful and change two opposing variables, they will cancel each other out and it’ll seem like you didn’t change anything at all.

We covered a good deal of ground on 3D rotations in SwiftUI, but what about an object?

Let’s focus on building a cube. It has six sides, although to keep things simple, I’m only going to worry about four of them. Two of our sides will start at 90 degrees, making them invisible, and two of our sides will be at 0 degrees (so face on). As we rotate things, we’ll need to use an offset on two of the faces to keep everything together. To help us get the rotation correct, we use a perspective value of at least 0.5 so we can see if we got it right as it turns. It helps too if we add a line of text to each face so that we can tell which way it is flipping as it turns. Sometimes, it isn’t so obvious. Finally, we use opacity as we build it to mask the faces that are good. Use opacity at the end to get your front and back visually looking right. Reduce the perspective to a minimum too. Otherwise, it simply won’t work.

Keep in mind as I said before that many of the parameters interact with each other, so be careful as you move forward not to change more than one at a time.

Follow those rules and soon you’ll find yourself looking at a cube just like this one — a cube you can leave as a wire frame or indeed add a skin to.

Rotating cube using SwiftUI.

Here’s the code for this GIF:

As I said, once built, you can add a skin too and some subtler shading. And there you have it: a 3D object in SwiftUI.