This tutorial will teach you how you can extract valuable information from time series, such as your sold copies on Steam or your Google Analytics. The previous part of this series introduced a technique called moving average, which has been used to attenuate the effects of noise in a signal. When signals represent an event that evolves over time, we are in front of a time series. Classical decomposition is a technique that attempts to find the main trends within time series.
This post will show how to simulate the diffusion of smoke using shaders. This part of the tutorial focuses on the Maths and the code necessary to recreate the smoke effect. To learn how to set up your project, check out the first part: How to Use Shaders For Simulations.
This tutorial is a primer on Voronoi diagrams: what they are, what you need them for and how to generate them using a Shader in Unity. You can download the complete Unity page in Part 4.
Part 1: Voronoi Diagrams
Technically speaking, Voronoi diagrams are a way to tassellate a space. It means that the end result of Voronoi is a set of “puzzle pieces” which completely fills the space. To start, we need a set of points (often called seeds) in the space. Each seed will generate a piece of this puzzle. The way Voronoi works is by assigning every point of the space to its closest seed. The final result heavily depends on the way distance is measured in the space.
Most Voronoi diagrams are are based on the Euclidean distance. The cost between two points is given by the length of the shortest segment which connects them both. It can be calculated easily with the Pythagorean theorem:
In Cg, this function is already implemented and is called
distance. The picture on the left shows a Voronoi diagram based on the Euclidean distance, drawn with 100 points. On the right, the same diagram uses a gradient to visualise the actual distance from a pixel to the closest one.
The distance diagram has been calculated using
minDist to sample a gradient from black to white.
As the name suggests, the Manhattan distance takes his name from the homonym city. The shortest path between two locations is not a straight line, since Manhattan is full of buildings. The shortest distance is the one which goes around building.
Compared to the Euclidean distance, It is sensibly less expensive to calculate.
Using the Manhattan distance produces very intriguing patterns which resemble circuit boards. This is not a coincidence: many boards are designed to minimise circuit length and avoid curves.
Despite looking very different, both the Euclidean and the Manhattan distances are both special cases of a more general metric: the Minkowsi distance. To understand why, you have to remind some algebra. In the same way multiplication and division are the same operator (dividing by is equivalent to multiply by ), even root and exponentiation are deeply connected. Remembering then , we can introduce the Minkowski distance:
When or it equivalent to the Manhattan or Euclidian distance, respectively.
The most fascinating aspect is that is provides a way to smoothly transitioning from the Euclidean to the Manhattan distance, and the other way round.
If you are in a higher dimension, the Minkowski distance can be still used, providing that you calculate it on all the components of two points and :
The next part of this tutorial will focus on the applications of Voronoi diagrams.
Part 2: Applications
Despite looking pretty, not a single application has been indicated for Voronoi diagrams yet. In actuality, they play a very important role in Science, and many games can benefits from them.
Breaking object realistically is a very challenging task, that requires to know how pressure waves propagates through a material. A simpler way to create plausible fractures in an object is to rely on a Voronoi 3D tassellation. You start choosing random points within the object you want to break, then each Voronoi cell become one of its chunks. In games, breakable objects don’t break: they are already broken, and your interaction makes the piece falling apart.
The famous Fracturing & Destruction plugin on the Asset Store, for instance, uses this technique to generate breakable objects. A future post will show how to replicate this effect at no cost.
In path finding
As a game developer, you might be familiar with path finding. A* is notoriously the most known, but there are many other ways one can find the optimal path between two points. So far, Voronoi diagrams have been seen as independent regions of space although there is an alternative way of interpreting them. If we put a node every time two segments connects, Voronoi produces a graph. The segments (now edges of the graph) represent the paths which are as far as possible from the seeds. In terms of gaming, seeds can be enemies you want to avoid; travelling on the edges provides the safest route possible. Brent Owens has written a very nice tutorial about this.
Conversely, Voronoi diagrams can be also used to approximate the shortest path. The dual graph of a Voronoi diagram (known as the Delaunay triangulation) allows to find paths which are as close as possible to the seeds. When coupled with the Manhattan distance, it can be used to generate the fastest route within a city, considering how fast you can go on different roads.
Circle packing is the problem of fitting as many circles as possible in a given space. The best possible solution to this problem is shown on the left; circles are arranged in a hexagonal lattice, which resemble a honeycomb. This is actually why honeycomb cells have a hexagonal structure: if all circle expands at the same time to fill all the space around them, they’ll end up pressing against each other until they create a perfect hexagonal lattice. The same pattern can be found in several other phenomena, like cooling magma and soap bubbles. The latter, provide an excellent (and transparent) example of how Voronoi diagrams look in three dimensions.
The next part of this tutorial will show how to generate Voronoi diagrams using Shaders.
Part 3: Generation
There are several algorithms you can rely on to generate Voronoi diagrams. Every point is independent from the other, so this is one of those perfect applications for a shader. Traditionally the Fortune’s algorithm (left) is commonly used, but it is very hard to implement within a shader. The tricky part, in this case, is how to provide a list of points to the Material, since the Unity APIs don’t provide any
SetArray function. Luckily, there is an undocumented feature you can use to pass arrays and matrices to a shaders, and it has been discussed in this post. We will use one array for the position of the points (in a 2D space) and another one for the colours. A variable called
_Length is used to indicate how many points are there since Cg doesn’t support arrays of arbitrary dimensions.
uniform half2 _Points;
uniform fixed3 _Colors;
The actual code of the Voronoi diagram is implemented in the fragment function. For each pixel, it simply loops over all the points and finds the closest one. Its index is then used to find the right colour to use:
Different types of diagrams are possible simply by replacing the function
distance with the appropriate metric. If you want to draw the distance diagram instead, you can sample a ramp texture using
minDist. You can also set the texture mode to “Repeat” rather than “Clamp” for some bizarre effects.
Weighted Voronoi diagrams
Interesting results can be obtained by mixing different metric, or altering the “attraction” of the seeds by providing an extra coefficient to the shader. The distance is now:
This takes the name of weighted Voronoi (also known as Dirichlet tessellation) and it can be used to generate beautiful effects, like Milan Domkář did with his foam:
There is a smarter approach to generate Voronoi diagrams (almost!) for free, and Chris Wellons is beautifully explaining it in its blog. You can generate a Voronoi tessellation by projecting cones out of the starting points. The cones will eventually intersect and seeing them it from the above will produce the same effect.
You can download the full Unity package in the last part of this tutorial.
Voronoi diagrams are a way to tessellate the space which has many applications, from game development to city planning. This tutorial has shown how to generate them using a shader; you can download the complete Unity package here.
This tutorial will introduce the Transformation Matrix, one of the standard technique to translate, rotate and scale 2D graphics. The first part of this series, A Gentle Primer on 2D Rotations, explaines some of the Maths that is be used here.
This tutorial will introduce rotations, translations and other affine transformations. This knowledge is essential not just for 2D games, but also to understand Quaternions and transformations in 3D games. This first post of the series is a gentle primer on 2D rotations.
This post discusses about the tricky problem of colour interpolation, and explores possible solutions. Many software and engines offer read-to-use functions to interpolate colours. In Unity, for instance,
Color.Lerp is available and does its job pretty nicely. Use the interactive swatch below to see how
There’s nothing wrong in using these functions, as long as you know what the deal with colour interpolation is.
Interpolation is a technique that allows you to “fill a gap” between two numbers. Most APIs expose linear interpolation based on three parameters: the starting point , the ending point and a value between 0 and 1 which moves along the segment that connected them:
When , is returned. When , is returned instead. The beauty of this formula is that is easy to understand, efficient to implement, and it works in any dimension. Lerping in two dimension only requires to independently lerp the X and Y components. Lerping always returns points on the line that connects and , regardless of the number of dimensions. A standard RGB lerp can be done as such:
If it’s true that linear interpolation works as expected in three dimensions, the same cannot say for colours. There’s a fundamental difference between the XYZ and RGB spaces: the way the human eye perceive colours. While it make sense to connect two points in a 3D space with a line, the same doesn’t always apply for points in the RGB space. Interpolating the R, G and B components independently offers no guarantee on the hue of the intermediate colours. As Stuart Denman highlights in his Improve Color Blending, the RGB space of cyan and red meet halway in grey. A new hue appears because the RGB space does not capture how Humans perceive colours very well.
The next pages of this post will explore better ways to interpolate colours.
A first attempt to compensate for this is to switch to different colour space, such as HSV (also known as HSB). It has been designed to be “artist-friendly”, grouping colours by hue and ignoring how they are created on screen.
The result, as it can be seen above, is rather disappointing. The reason is that interpolating the H component cycles through different hues. In this case we don’t have to go through green, but looping over the H space in the opposite direction.
To implement an HSV lerping function we need to understand how these components are handled. For this example, we’ll assume all the HSV components range from 0 to 1. The following code is inspired from Improved Color Blending and relies on the ColorHSV Unity extension by C.J. Kimberlin:
For comparison, the linear lerping through HSV space is also shown together with the corrected lerping (HSV*).
Despite all the effort, the transition still doesn’t look good. The reason is that even if we have correctly learped through the Hue component, different colours have different luminosities. As explained by Gregor Aisch in How To Avoid Equidistant HSV Colors, equidistant colours in the HSV space are not perceived as really equidistant. Even HSV colours with the same brightness (V) can differ in their perceived brightness and luminosity. Many aspects are responsible for this. The R, G and B components of a colour contributes in different ways the perceived luminosity, due to the way their respective photoreceptors work. Several attempts have been made to capture the non-linear relationships between R, G and B in a colour model. One of the most successful is the LCH (also known as HCL for Hue, Chroma and Lightness). Equidistant colours in the LCH space are also perceived as equidistant. The swatches below clearly shows how the LCH space provides a more uniform distribution of the colours.
The conversion from RGB to LCH is very expensive. This is because colours have to be converted into to intermediate spaces, the XYZ and LAB. A very good library which supports all of these conversions is chroma.js.
Using colours with equidistant perceived luminosity is essential for all these applications in which colours have a precise meaning, such as diagrams and heatmaps. Providing uniform luminosity is also important for colour blind people, as discussed in Accessibility Design: Color Blindness. A starting point to design a safe colour palette is ColorBrewer.
Interpolating colours by lerping their RGB components is the most common and lazy easy approach to tackle a very complex problem. If the interpolated colours need to be visible at the same time (for instance in a chart or a diagram) chances are you might need a more advance technique. Conversion from RGB to HSV are supported by most frameoworks, but if you want to go the extra mile you should adopt the LCH colour space.
This post was strongly inspired by the many works of Gregor Aisch.
This post is for all the developers and mathematicians out there that are curious to explore and visualize the bizarre properties of numbers. Although Maths plays an important role in today’s technology, many people likes to abuse it for recreational purposes. Part of the appeal of Recreational Maths lies in the challenge to discover something new. Despite what many believe, finding mathematical patterns is very easy; it’s discovering something useful that is incredibly challenging. If you’re up for such a challenge, this tutorial will teach you how to use Python to calculate some of the most infamous numerical sequences.