Shader Series, Part 1: Color Transitions

This is part one of Made with Mustard’s Shader Series, showing all kinds of cool stuff you can do with shaders and the Corona SDK. Not sure what you’re reading? Let’s start at the start.


The Corona SDK packs a lot of power, but it doesn’t always have a built-in solution for every need. In a lot of cases, though, shaders can step in and fill in those blanks. Want to smoothly animate a shape’s fill between two different colors?

Here’s how to do it.

The Shader

Stick this in a dedicated .lua file for shaders somewhere in your project, and be sure to require it in your main.lua.

local one = {}
one.category = "filter"
one.name = "one"
one.vertexData =
{
    {
        name = "r",
        index = 0,
        default = 0, 
		min=0,
		max=1,
    },
    {
        name = "g",
        index = 1,
        default = 0,
        min = 0,
        max = 1,
    },
    {
        name = "b",
        index = 2,
        default = 0,
        min = 0,
        max = 1,
    },
    {
        name = "dt",
        index = 3,
        default = 0,
        min = 0,
        max = 1,
    },
}
one.fragment =
[[
    P_COLOR vec4 FragmentKernel(P_UV vec2 pos){
        P_COLOR vec4 from = CoronaColorScale(texture2D(CoronaSampler0, pos));
        P_COLOR vec4 to = vec4(CoronaVertexUserData.r, CoronaVertexUserData.g, CoronaVertexUserData.b, from.a);
        return mix(from, to, CoronaVertexUserData.a);
    }
]]
graphics.defineEffect(one)

How to Use It

local size = screen.w * 0.25
local rect = display.newRect(screen.center.x, screen.center.y, size, size)
rect:setFillColor(231/255, 76/255, 60/255, 1)

rect.fill.effect = "filter.custom.one"
rect.fill.effect.r = 0.2
rect.fill.effect.g = 0.53
rect.fill.effect.b = 0.98
rect.fill.effect.dt = 0
transition.to(rect.fill.effect, {dt=1, time=5000})

In this example, we’re creating a standard rectangle and assigning it a starting fill color. The custom fill effect takes 4 properties: r, g, b, and dt. The first three are what you’d expect, being the red, green and blue properties of the destination color, while the last is a number between 0 and 1 to indicate how much to transition.

dt=1 configures a full transition between the starting color and ending color, whereas dt=0.5 would only go halfway. In general, you’ll probably want to stick with dt=1.

A Few Things to Consider

  • Take note that you’re transitioning the rect’s fill.effect, not the rect itself. You can still run your other transitions on the rect as normal, but they’ll operate independently of the color transition, and you might have to work a little to keep them in sync.

  • This particular shader uses the mix function between the two colors. This is a very basic linear interpolation. There are other methods that could be used to achieve a better transition, or a different end result (think additive, multiplicative, and other color blending modes). For our purposes, though, this simple effect did the job just fine.

Conclusion

Color transitions are a common request in Corona, but it took us more than a few tries to realize that shaders are an effective—and powerful—solution to the problem. In the coming weeks, we’ll design a shader that can fade an object out from top to bottom, show you our nifty scrolling Tiny Boxes title screen effect, explore randomly generated noise, and more.

Until next time!

Share

Game talk. Dev talk. Good humor.

Join the newsletter for weekly updates on how to make (and market!) ridiculously charming games.