LOG_01: GRADIENT MAPPINGDegradation of information is a key theme in the game. We’re threading this into the art by emulating various forms of image compression/reduction, mainly through a lot of custom post-processing.
One effect recently added is
gradient mapping. We thought it would be interesting to use for color grading (where we already have a slew of other stuff happening) and other more glitchy output.
What is gradient mapping? If you’re an artist, you might have used this
Photoshop tool:
In short, (greyscale) values of the source image are mapped to a gradient. The darker values are replaced by color on the left side of the gradient while lighter values are replaced by colors on the right. Pretty simple.
This might work nicely in Photoshop, but we’re using Unity3d and we want to achieve this same effect in real-time. In our case we want to apply it to the whole screen as a postprocess. This means replicating the effect in a shader.
Here’s an excerpt of our shader with the relevant sections:
//This is a variable in the shader.
static const float3 ColorLuminanceWeights = float3(0.299, 0.587, 0.114);
//This is a function inside the shader.
float GetPixelLuminance(float3 color)
{
return dot(color, ColorLuminanceWeights);
}
//This is the fragment shader.
float4 frag(v2f i) : SV_Target
{
//_MainTex is the rendertarget.
float4 finalColor = tex2D(_MainTex, i.uv);
//Get the grayscale value of the pixel.
float pixelLuminance = GetPixelLuminance(finalColor.rgb);
//Use the grayscale value as the x-coordinate of the UV for the gradient map texture.
finalColor.rgb = tex2D(_GradientMapTexture, float2(pixelLuminance, 0));
return finalColor;
}

So, that’s actually very simple. But you may have noticed we need one thing, a gradient map texture. This texture will usually look something like this:

The gradient map texture is 256 pixels wide because there’s 8-bit per channel in the shader which means 256 values (0 - 255). This means we can map 1 value to one pixel on the gradient.
This is our scene with regular postprocessing(before):

Here’s an example of an extreme gradient map being applied(after). In this case I used the 4 color palette from the original Game Boy.


Voila!
Though we wouldn’t use this ‘Gameboy’ treatment exactly as is, there are definitely scenes where we’ll work with as little color: Maybe less

We really want to explore the full range of the emergent beauty of image degradation.
There’s a lot you can do to take this even further:
- Add a lerp to blend between the rendertarget and the gradient mapped colors.
- Add controls for the y-coordinate of the UV (in combination with multiple gradients in one texture).
- Add panning or Distortion to the UVs for some crazy effects.
Here’s a gif transition, applying a very incorrect

c64-ish palette via in-game blending volume:

