3 Magic Numbers in a Colour Replacement Shader

Posted by aBethke on Sunday Jan 14, 2018 Under Bag o' Tricks, Unity

Recently at work I was developing a shader for doing colour replacement. I wanted to create a palette of five colours and have a shader that would replace colours in a source image, video, model, or work as a post-processing screen effect. After four versions I got the types of results I was hoping for and I wanted to share a breakdown of the technique I was using to do the replacements and note a few interesting things I learned along the way including the mystery of these magic numbers: 0.3, 0.59, 0.11.

High resolution clown image from the movie It

Pennywise from the movie IT, used as a test image for the shader development

The first version of the shader was very simple. It looked at the rgb colour of the current pixel and then tried to match it to the closest matching colour from the pallette. The first really interesting thing I learned while building this version was to think of RGB values like a 3D point. This was significant for me because I previously didn’t have a good way to think of colour values in a way that could be compared but after stumbling on a forum post where someone said to think of the RGB values this way it made it really easy for me to visualize the data. At this point I wrote some shader code to take the current pixel colour and compare the distance to the palette colours and then replace with the closest match. This worked as a basic first approach but there was a lot of detail loss.

A low detail colour replaced version of the Pennywise test image

Five colour replacement shader, version 1

For the second version I tried adding a parameter to the shader called Strength which was used to blend the replacement colour back into the original image. This way I could turn down the blending strength to retain some of the detail. The result was a slight but noticeable improvement but still not good enough for what I was going for.


An improved detail colour replaced version of the Pennywise test image

Five colour replacement shader, version 2

In version three I started taking a different approach after having the idea that if I convert the image to grayscale first there would be a better match for colour replacement, better blending, and ultimately better detail retention on the overall picture. In figuring out how to convert an image to grayscale I found a line of code that had three magic numbers.


float3 greyScaledColour = dot(sampled.rgb, float3(0.3, 0.59, 0.11));


I didn’t understand what this code was doing but it clearly resulted in a grayscale image so I integrated it into my shader. It really bugged me that I was using a piece of code I didn’t understand so I showed it to my team lead at work and we began a discussion and some investigation to find the source of the numbers. After some back and forth my lead had an idea that was quickly verified and while still not fully understanding why this results in a grayscale pixel when using the dot product of the sampled colour against these three magic numbers what we did find is the source of the numbers. These numbers correlate to the number of Red, Green, and Blue rods and cones we have in our eyes. WILD!

Here’s some links to some of the info we read that led to this understanding.


So after converting the image to grayscale and then doing the colour replacement there was a further improvement as I had hoped. If you compare the v3 image to the v2 image it’s hard to notice the difference at first but if you look at the head of Pennywise in v3 you should notice that the colour gradiation resulted in better groupings of colours whereas in v2 there’s a split on the forehead between blue and pink areas that seems unnatural even in this extreme palette.


Third version of the colour replacement shader output.

Five colour replacement shader, version 3

At this point I was pretty happy with the shader but had one more idea that I thought might yield an even better result, which proved to be true. The final technique worked better than the previous versions and gave you a lot of control over how the colour replacements are done. So here’s what I did…


I realized that I could treat the grayscale colour values as a single number in the range of 0 to 1. I could also take the 5 colour palette and treat those values as a range of 0 to 1. Now instead of doing distance checks on the three values I would just be matching the 0 to 1 values between the grayscale and the replacement palette. From there the final step was to add some sliders to the shader so you could control the thresholds for each colour in the palette which gave you much better control of which colours replaced dark and light areas in the image. Once that was all done then the final value was blended as in the previous versions for the end result. I am extremely happy how this shader turned out and am already using modified versions of it in a number of projects.

Final version of the colour replacement shader using the Pennywise test image

Five colour replacement shader, version 4

Tags : | Comments Off on 3 Magic Numbers in a Colour Replacement Shader

Parallax: A simple solution

Posted by aBethke on Friday Jun 18, 2010 Under Bag o' Tricks, Game Development

Recently when I was working on Star Fall I needed to develop a basic Parallax implementation as part of the game design. Ive done this type of implementation before but never built anything reusable. In fact, I’d love to tell you now that I did just that when developing Star Fall but that, sadly my friends, would be a lie. I have however taken the code I wrote for Star Fall and developed it into a very basic Parallax system which I offer up now to the gods of the interwebs and anyone else that might be interested.

The basic breakdown is pretty simple. You instance the SimpleParallax class and then begin adding layers to it and defining their properties via the methods I have created. The layer handling system uses a name to keep track of the layers. When you create a layer you assign its name and then reference it layer via the same name. There is no active depth sorting, simply create the layers in the order you wish them to appear.

[cc lang=”actionscript3″ line_numbers=”true” no_links=”true” width=”100%”]
package com.goldengear.core
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;

public class SimpleParallax extends Sprite
public function SimpleParallax()
mouseEnabled = false;
mouseChildren = false;
addEventListener(Event.ENTER_FRAME, handleEnterFrame, false, 0, true);
protected function handleEnterFrame(in_event:Event):void
var i:int;
var num:int;
var layer:DisplayObject;
var layerName:String;
var scrollSpeed:Number;
var loopX:Number;

if (!isPaused)
num = m_layerNames.length;
for (i=0; iSimpleParallax – Test Application

As I poke at this class more I will probably release the updated versions. Enjoy!

Tags : , , | Comments Off on Parallax: A simple solution

This is a trick I picked up recently when I was preparing some games (Mashin’ Meeces and Star Fall) for release on portal sites and saw that it would be a bit easier (and required by some) to figure out how to change my multi-SWF application into a single SWF app.

Mashin’ Meeces was originally broken into three SWFs: game code, art assets and sounds. I did this so that I could work on the game independently from the sound or art since those were being taken care of by other people. Through my previous experience developing games I had never run into a problem with having games broken into multiple SWFs before but those projects have all been for private sites and game portals like Newgrounds and Kongregate are a new experience for me. After talking with my colleagues, doing some research and poking at the code for a bit I finally got the solution of embedding the SWFs into my main application and then load them using loadBytes.

Here is the code I used to embed the two SWFs (art and sounds) into the main class of my ActionScript project.

[cc lang=”actionscript3″ line_numbers=”true” no_links=”true” width=”100%”]
[SWF(width=’800′, height=’600′, backgroundColor=’0xffffff’, frameRate=’30’)]
public class MashinMeeces extends Sprite
[Embed(source=”MashinMeecesAssets.swf”, mimeType=”application/octet-stream”)]
private var swfAssets:Class;
[Embed(source=”MashinMeecesSounds.swf”, mimeType=”application/octet-stream”)]
private var swfSounds:Class;

public function MashinMeeces()
// Rawr! I am the constructor…

For the loading I had just been using a standard Loader implementation and to convert the pre-existing code all I had to do was drop the URLRequest() and change load() to loadBytes().

[cc lang=”actionscript3″ line_numbers=”true” no_links=”true” width=”100%”]
protected function addedToStage(in_event:Event):void
var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);

var assetLoader:Loader = new Loader();
assetLoader.visible = false;
assetLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, assetsLoaded, false, 0, true);
assetLoader.loadBytes(new swfAssets(), loaderContext);

Tags : , , , | Comments Off on Actionscript Project Refactors: Multiple Swf to Single Swf Loading

Timers can suck it

Posted by aBethke on Tuesday May 4, 2010 Under Bag o' Tricks, Game Development

Salvidor Dali PaintingI think the title of this post really sums up my entire sentiment as far as the Timer class goes in Flash. Many people have recently heard me speaking, arguably ranting, on the subject so I thought I would quickly highlight a few reasons to avoid using Timer, the one place that I have found that I had to use Timer and offer an alternative piece of code to use in the majority of cases where a timer like mechanism is needed.
Read More

Tags : , , | Comments Off on Timers can suck it