Hue-Based Palette Swapping Using Shaders
Alright, posting a Friday blog post on a Friday. What a milestone! I'm extremely tired today, but determined to make this post happen, so through sheer force of will, I shall now type.
Let's talk about some technical stuff today. One of the goals for this week was to design the basics of our sprite system. A key design philosophy in Harmonia is that the creation of new assets must be accessible, or, as I like to think of it, as lazy as possible. I want the engine to handle as much as it possibly can for me before I resort to making another batch of artwork or 3D models. With that in mind, I want to get as much mileage as possible from the game's sprites, so I want to have color-swapping effects like in JRPGs of yore.
Here are some sprites from Final Fantasy IV that take advantage of this:
The catch is, making indexed-color sprites is a bit of a pain and it limits the number of colors you can use, which, in turn, restricts the game's aesthetics. Furthermore, reselecting the palette for every color of a 256-color sprite would be more trouble than it was worth. In the end, I ultimately want to draw 32-bit RGBA images using Photoshop or Gimp.
So, if the image isn't using an indexed color palette, the various color regions of a sprite must be marked so you can modify only specific colors. For example, you may want to change the armor color of a Warrior but leave the skin and eye color intact. One way to do this is to manually define color regions for each frame, but this is extremely tedious. The method we used is to define color regions by using unique hues in the image itself:
He may look like a zombie with poor fashion sense, but this image was easy to create, and the scripting to define regions is beautifully simple:
region skin grey region arms red region shirt green region eyes blue region hair brown region legs purple
At this point, Harmonia takes our image and rebuilds it as an HSV map. The red channel represents the closest matching region color: 0 for skin, 1 for arms, 2 for shirt, and so on. Here is the image, not meant for human eyes to decipher:
Blech. Anyway, now that this color map is built, we can define our own color regions which we'll eventually pass to the shader. When assigning a sprite to a mob, we can simply use the following commands:
# set the sprite. set ("sprite", "harmonia_guy") # define these colors as an RGBA value... set ("color_skin", "255 160 64 255") set ("color_arms", " 96 96 128 255") set ("color_shirt", "128 255 128 255") # ...and these colors as a web color. set ("color_eyes", "blue") set ("color_hair", "brown") set ("color_legs", "tan")
Now that we've assigned some color data, we can pass it along to a shader to draw and render our completed sprite:
With this system in place, it's possible to modify specific colors of a sprite in the scripting environment. For example, the Berserk condition may give a character's skin a red hue, while the Banish spell may change everything but one's eyes to be 75% transparent. It also allows for random colors to be assigned, like in this image here:
So, now that this part of the engine is finished, I need some real artwork with good animations... If you know a good artist, I'll pay him double my salary. Which is nothing. See what I did there? Yeah, okay, time for bed.