MZR: Gradient Based Shader Effect

Posted on

Today I’ll talk about a shader idea I’ve always wanted to use but never got to release in a game until now. It has its roots in the old retro palette scrolling technique – or at least was inspired by it.

Palette scrolling was the thing when images had 8 bit pixels with each pixels being an index into a palette table of 256 RGB entries. That way using the same image and just changing the palette, one could change the look of the image without actually altering any pixels. Artists would do wonderful animations with just changing palettes. One of the cheapest way to do that would be to just shift the palette one entry (scroll it) and then see the colours shift – I called that palette scrolling.

These days one can still do palette scrolling but on current GPU hardware that involves using two textures: one index texture and one 1D palette texture. Animation being achieved by dynamically changing the palette texture. While on desktop GPU hardware that’s entirely fine on current mobile device GPUs dependent texture fetches are not very performance friendly.

I wanted to use a similar concept of having a static texture that would change appearance when “something like a palette” would change.

I do that by exposing a range from a gradient texture using a step function. For a quick refresher on the topic, have a look at this excellent post on step and pulse functions: http://realtimecollisiondetection.net/blog/?p=95

By using a gradient texture and a step function, y = sat(ax + b), I can vary the parameters and a and b and reveal/animate different parts of the said texture. I also introduce two colours and interpolate between then based on the y value.

Here is the shader code:


uniform mediump vec2 GradientParams;
uniform lowp vec4 GradientColour0;
uniform lowp vec4 GradientColour1;

...

mediump vec4 col = texture2D(Texture, texVar);

// calculate a*x + b
mediump float y = col.x*GradientParams.x + GradientParams.y; 

// calculate sat(a*x + b) by clamping
y = clamp(y, 0.0, 1.0); //sat (a*x + b)

// interpolate the two colours based on the resulting y value
lowp vec4 rcol = GradientColour0*(1.0 - y) + GradientColour1*y;

// factor in the original texture alpha
col.xyz = rcol.xyz;
col.a *= rcol.a;

//apply the variant colour
gl_FragColor = col*colorVar;

The a and b parameters go in the GradientParameters x and y components and two colours at each extreme is respectively GradientColour0 (for y=0) and GradientColour1 (for y=1).

Let’s take a simple gradient texture:

h_grad
A horizontal gradient texture.

And then apply our shader to it. We are using the function y=sat(ax+b). We use a=1 and b=0 thus giving us a gradient of 0 to 1 in the range of the texture. Then we are going to assign a colour at y=0 to be white (255,255,255) and at y=1 we’ll assign it to be black (0,0,0). Here’s how that would look.

Reverse: Using the gradient but replacing colour 0 to be white and colour1 to be black.
Reverse: Using the gradient but replacing colour 0 to be white and colour1 to be black.

 

Next let’s try to use a part of the range. We’ll use the same function but use a = 3.3 and b=-0.9. That way y will be 0 until x reaches 0.3 and then grow linearly to 1 until x reaches 0.6. To illustrate that I’ve assigned colours to be red for y=0 and blue for y=1.

grad_example2
Note how gradient transition between the two colours happens int he range 0.3-0.6 that we have isolated using our two parameters.

 

Here’s one based on the same gradient texture that illustrates the way I use this effect. I assign a=2 and b=0 and that gives me a gradient between 0 and 0.5. I also assign the y=1 colour to be translucent – alpha=0.0. That way by varying the parameter a with some dynamic game value, I can get the bar to move with that value.

Gradient based on parameter going into translucency.
Gradient based on parameter going into translucency.

In MZR I link a lot of effects to the music EQ so that visuals appear to bounce with with music.

The above examples are using our simple horizontal gradient texture. Things get a bit more interesting as we start using more complicated textures. For example here’s the actual texture I use for my effect in MZR and the final result next to it. The green MZR logo in the texutre is to indicate where the start of the gradient is – it’s a grey gradient that fills up a maze.

Gradient texture for a maze that the shader works with.
Gradient texture for a maze that the shader works with.
The final result in MZR. The parameter a is controlled by the base frequency in the music animating the maze on the screen.
The final result in MZR. The parameter a is controlled by the base frequency in the music animating the maze on the screen. Note: this also has the MZR logo rendered on top as well as the FUNKY CIRCUIT sign.

 

 

 

 

 

 

 

 

 

 

 

And here’s the intro sequence to MZR where this effect is used:

 

The parameters are linked to the music EQ. The video shows the effect which is a single render call as well as the logo rendered on top and a FUNKY CIRCUIT sign underneath.

 

That’s it for now. See you next time.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s