Procedural Color Algorithm

Shahriar Shahrabi
7 min readFeb 21, 2019

--

Beautiful colors can change everything in a game or an artwork. Using simple mathematics, you can write algorithms that deliver harmonious color schemes with high consistency. I am going to share one of these algorithms and explain why and how it works, and give applied examples which I have used for real time graphics and my own paintings. This algorithm can be used both in the CPU or GPU, and in any environment such as Unity, Unreal or Photoshop scripting. If you just want the algorithm, jump to the last section. Big Gifs ahead, so bare with me on the loading time.

A Popular Color Theorem

If you change from traditional paintings methods to a digital one you would realize that more freedom and ease of access in your choice of color doesn't equal better color palettes. It was around the time I started with digital painting that I read Color and Light from James Gurney. Gurney’s approach to color theorem is a very simple one. The idea is that you pick a few key colors, and mix the rest of your palette by combining these key colors. In the language of computer graphics this would mean that you cut out a part of the color space, and use only colors which are within that extracted volume in your render/ painting. For simplicity, lets assume the calculations to happen in the Hue Saturation Value color space and all four colors have the same values (darkness). The four points create a quad on the surface of the color wheel. The idea is that if you only use colors on the surface of this quad, you achieve a harmonious color scheme. You could of course do this for any give number of key colors. Though at some point it will become redundant.

The following is the first time I used Gurney’s simple method for building my palette. Though more limited in colors, it felt more harmonious to me. The color wheel on the right is the actual key colors used for the painting, however values are not constrained in this painting by the key colors. Only hue and saturation.

In Real Time Application

As we were developing Superflight, one of the main challenges was to create variation in the aesthetic of the procedural levels our level generator made. Varying colors and generating palettes in run time was one of the easiest methods to achieve this. Friedemann who did most of the art direction for the game, wrote an algorithm based on Gurney’s theory to generate harmonious color palettes for each individual level in run time. In each level, the color generator would create four key colors which are passed to the shaders of the geometry. The shaders calculate the color of their fragments by linearly interpolating between the key colors using a predetermined RGB noise, which was projected on top of the geometry using triplanar mapping. This worked really well, and created tons of unexpected color palettes, which I would have never consciously hand picked, because of their unconventional key colors (such as combining magenta, with yellow and cyan). The basic formula was:

float4 EndColor = lerp(keyColor1, keyColor2, random1);
EndColor = lerp(EndColor, keyColor3, random2);
EndColor = lerp(EndColor, keyColor4, random3);

After the development, I wondered if I could use this method to speed up the experimentation phase and choosing of color palettes for my illustrations. I first wrote a Photoshop script, which received 3 to 4 key colors and generated the rest of the palettes for me. You can download the scripts here. Then I did around 15–20 paintings to make sure the method can generate harmonious color schemes. Which I was quite satisfied with.

Here is a color palette which the script generated for me in Photoshop, and the results which I used for a scene:

Next step happened in Unity. This application automatically remaps the color scheme of an image to a new one with the given key colors. The key for this experiment was to use the HSV color space for remapping, so that I can keep the values of the pixel (lightness or darkness of the grey scale) constant and just change hue and saturation. You can view the application here.

At this point there was one main issue in the algorithm. The sampling had a statistical bias. I won’t describe it in details, since I will be sharing a newer sampling method, but in the old method the last key colors were statistically favored, so if the fourth key color was blue, and the first red, you rarely saw any red and almost always saw blue shifted colors. I fixed this in my next experiment, by using a formula to receive a point on a surface of a triangle with a more uniform distribution. I got this sampling method from here. The result was this:

Which Color Space?

The question of which color space to use is an important one. In the current version of the algorithm, the RGB color space is used. This is mainly because of performance reasons. I have experimented with using a corrected artist color wheel, which results in a more consistence harmonious color schemes, specially around the hue Green. Consider the following situation. We cut the same triangle out of two different color spaces. The HSV color spaces and the artists color wheel. As you can see the color green takes a huge chunk of the HSV color space, as well as the RGB one. However in the artists color wheel, this has been corrected so that each major hue occupies a similar segment of the circle. So the same cut can give us different palette, in different color spaces.

This is one of the many things to consider. It is not only the hue that is not evenly distributed across the color wheel with respect to our psychologically perceived notion of color, also the relationship between a color’s saturation and its value, with regards to its hue is a complicated one. Given the maximum Saturation and value for both color Red and Yellow, the Yellow is still perceived as lighter, and the red darker. The algorithm itself is simple, but the holy grail is in constructing a perfect color space for it.

A Simple Line To Copy

Having explained the idea behind it, here is the line you need to copy in your projects. For more details you can have a look at this shadertoy page , where I use this algorithm to generate endless procedural colors.

Step 1: Create a system where Key colors are generated. This can be chosen by the artist, or dynamically generated using random functions. Here is an example of how I am doing it.

ExampleKeyColor = new Vector3(
abs(sin(iTime+12.) + sin(iTime*0.7 + 71.124)*0.5)
,abs(sin(iTime) + sin(iTime*0.8 + 41.)*0.5)
,abs(sin(iTime+61.) + sin(iTime*0.8 + 831.32)*0.5))

Step2: Every time you want a color from the current color scheme, call the following function, while providing it with two random seeds which range between 0 to 1, and three Key colors.

Color SampleFromColorScheme(float r1, float r2, Color _Color1, Color _Color2, _Color3){
return (1. — sqrt(r1))*_Color1 + (sqrt(r1)*(1. — r2))*_Color2
+ (r2*sqrt(r1)) * _Color3;
}

Step3: Use this color. For example you can determine the color of the light, the ambient light, sky box, individual assets and etc. by calling this function with unique seeds. The more iteration between key colors you create, the better it will look.

Reflection

This is not the only way to get a harmonious color schemes and it is not an iron rule. Using this approach, you will miss on lots of possible amazing color schemes. As an artist the best source for choosing a color scheme is still your experiences as an individual. However for real time procedural graphics, given the variation which this algorithms provides, its consistency makes it really useful. I find my self using it regularly in projects for almost everything.

If you develop cool stuff with it, let me know, specially if you created an awesome corrected color space. Either way thanks for reading and for any questions, get in touch.

Twitter: @IRCSS

--

--

Shahriar Shahrabi
Shahriar Shahrabi

Written by Shahriar Shahrabi

Creative Lead at Realities io, Technical Artist

No responses yet