This is the first part of a tutorial series about the basics of rendering. It covers transformation matrices. First, go through the Mesh Basics series, which starts with Procedural Grid. Then you will know how meshes work. This series will explore how those meshes actually end up as pixels on a display.

This tutorial was made with Unity 5.3.1.

Create a grid object, add our component, and hook up the prefab. When entering play mode, the grid cube will appear, centered on our object's local origin.

I'll use a default cube as a prefab, scaled to half size so there's room between them.

The most obvious shape of our grid is a cube, so let's go with that. We center it at the origin, so transformations – specifically rotation and scaling – are relative to the midpoint of the grid cube.

Sure, you could use a particle system as well. I won't because particle systems deserve their own topic.

Moving, rotating, and scaling a mesh is done by manipulating the positions of its vertices. This is a transformation of space, so to see it in action we have to make space visible. We can do this by creating a 3D grid of points. The points could be any prefab.

You already know what meshes are and how they can be positioned in a scene. But how does this positioning actually work? How does a shader know where to draw? Of course we can just rely on Unity's transform component and shaders to take care of it all, but understanding what's actually going on is crucial if you want to gain total control. To understand this process fully, it's best if we create our own implementation.

Transformations

Ideally, we should be able to apply an arbitrary amount of transformations to our grid. And there are many types of transformations that we could dream up, but let's restrict ourselves to positioning, rotating, and scaling.

If we created a component type for each transformation, we could add those to our grid object in any order and quantity that we want. And while the details of each transformation is different, they'll all need a method to apply themselves to a point in space.

Let's create a base component for all transformations, that they can inherit from. This will be an abstract class, which means that it cannot be used directly, as that would be pointless. Give it an abstract Apply method that will be used by the concrete transformation components to do their job.

using UnityEngine; public abstract class Transformation : MonoBehaviour { public abstract Vector3 Apply (Vector3 point); }

Once we add such components to our grid object, we'll have to retrieve them somehow so we can apply them to all our grid points. We will use a generic list to store references to these components.

using UnityEngine; using System.Collections.Generic; public class TransformationGrid : MonoBehaviour { … List<Transformation> transformations; void Awake () { … transformations = new List<Transformation>(); } }

Now we can add an Update method which retrieves the transformation, then loops through the entire grid and transforms all of our points.

void Update () { GetComponents<Transformation>(transformations); for (int i = 0, z = 0; z < gridResolution; z++) { for (int y = 0; y < gridResolution; y++) { for (int x = 0; x < gridResolution; x++, i++) { grid[i].localPosition = TransformPoint(x, y, z); } } } }

Why get the components each update? This allows us to mess around with the transformation components while remaining in play mode, immediately seeing the results.

Why use a list instead of an array? The most straightforward version of the GetComponents method simply returns an array with all components of the requested type. This means that a new array gets created every invocation, which is each update in our case. An alternative version has a list parameter. The advantage of that one is that it will put the components in the list instead of creating a new array. It is not a crucial optimization at all in our case, but it is a good habit to use the list variant whenever you're grabbing components often.

Transforming each point is done by getting the original coordinates, and then applying each transformation. We cannot rely on the actual position of each point, because those have already been transformed and we don't want to accumulate transformations each frame.

Vector3 TransformPoint (int x, int y, int z) { Vector3 coordinates = GetCoordinates(x, y, z); for (int i = 0; i < transformations.Count; i++) { coordinates = transformations[i].Apply(coordinates); } return coordinates; }

Translation Our first concrete component will be for translation, which seems the simplest. So create a new component which extends Transformation , with a position to be used as a local offset. using UnityEngine; public class PositionTransformation : Transformation { public Vector3 position; } At this point the compiler will correctly complain that we're not providing a concrete version of Apply , so let's do that. It's simply a matter of adding the desired position to the original point. public override Vector3 Apply (Vector3 point) { return point + position; } Now you can add a position transformation component to our grid object. This allows us to move the points around, without moving the actual grid object. All our transformations take place in the local space of our object.

Transforming the position.

Scaling Next up is the scaling transformation. It's almost the same as positioning, except that the scale components are multiplied instead of added to the original point. using UnityEngine; public class ScaleTransformation : Transformation { public Vector3 scale; public override Vector3 Apply (Vector3 point) { point.x *= scale.x; point.y *= scale.y; point.z *= scale.z; return point; } } Add this component to our grid object as well. Now we can scale the grid too. Note that we're only adjusting the positions of our grid points, so scaling won't change the size of their visualizations.

Adjusting scale. Try both positioning and scaling at once. You will find that the scale also affects the position. This happens because we first reposition space, and then scale it. Unity's transform component does it the other way around, which is much more useful. We should do so as well, which can be done by reordering the components. They can be moved via the pop-up menu under the gear icon at the top right of each component. Changing the order of transformations.