0
\$\begingroup\$

I am looking for a way to duplicate this color shifting effect:

Color shifting effect

I don't think it matters but the starting frame would be this:

Starting frame

My instinct was that some type of hue shift is occurring in a way that causes it to loop back over. The problem arose when I saw that the source of this effect was taking any image of any color palette and reducing it to this effect, always taking 14 frames to finish the loop.

Input frame:

Tree Start

Result of effect:

Tree Shifting

I'm not sure how this effect is being performed, I'm hoping someone will be able to help me duplicate it. This is for a game where I'm using C#. If I can get something working in C# I'll probably move it over to a shader. I'm using the MonoGame platform.

\$\endgroup\$
  • \$\begingroup\$ It is cycling the brightness of a set hue. \$\endgroup\$ – jgallant Jul 4 '16 at 21:36
3
\$\begingroup\$

The effect you're going for is less of a pure hue shift and looks more like old-school palette shifting effect. On old hardware this was implemented by arranging the color palette used for the image such that there was a run of similar colors (for example, a series of blues increasing in saturation, in the case of your first image) and then shifting and rotating the values in that palette by one (modulo the palette size).

Most modern hardware does not support palette images or rendering.

However, you can simulate the effect fairly easily by creating a 1D texture that contains the range of colors you'd like to cycle through. This will serve as your palette. You'll also want a texture that represents which part of that palette to sample for any given fragment being rendered. This index texture is essentially a grayscale version of your sprite.

enter image description here

Each texel in the index texture/sprite is actually a texture coordinate that looks up a position in the 1D palette texture. In your shader, simply read the index texture and use that result to look up into the color palette texture:

// Since the index is grayscale, you only need to deal with one
// component of the resulting color.
float index = texture2d(textureCoordinates, yourIndexTextureSampler).r;
vec4 color = texture1D(index + shiftUniform, yourPaletteTextureSampler);
...

The gray values in the index texture should be based on the number of colors in your palette. Let's say you have eight values in your palette and your index texture uses 8 bits per component. You'd use colors like the following in your index image:

0, 0, 0        palette entry 0
32, 32, 32     palette entry 1
64, 64, 64     palette entry 2
...

All you're doing here is dividing up the color space in the index image into eight discrete buckets so that when you feed that color (which the hardware will turn into value between 0 and 1 for you) back into the dependent texture read for the color texture you'll get the appropriate color (because that texture is also broken up into eight discrete chunks, one for each color in the palette).

That will give you a basic approximation of palette-based rendering. To implement shifting, simply add a uniform that represents the shift (which varies over time) and add that to the sampled index value, modulo the range of the palette. In the shader example above, there's no explicit modulo operation because texture address wrapping can take care of it for you.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks Josh, I've deleted the post from SO. Can you expand on the index texture more? I'm trying to figure out how I'm going from a pixel in the grayscale sprite (index texture) to an index into the palette texture. If possible, an example would be helpful. Creating the texture for the color palette is simple, there are 8 colors. How am I converting a range of RGB grayscale pixels to an index of 0 to 7? \$\endgroup\$ – test Jul 4 '16 at 21:55
  • \$\begingroup\$ @test You just read them directly from the texture and feed them directly to the next texture read; as long as you pick colors that are quantized into the desired number of buckets (the same as the number of colors your palette texture contains). \$\endgroup\$ – user1430 Jul 4 '16 at 23:16
  • \$\begingroup\$ Really struggling to get this working properly. It's as if it half works. But it doesn't do things that I expect it to do. For example, if I have a 16x1 texture as the texture to cycle through, and I refer to an index in that palette like so: tex2D(colorMap, float2(0,0)) shouldn't this take the pixel at 0,0 in my color map? Also, shouldn't I be able to advance to the next index (if I just want to preview it) by going tex2D(colorMap, float2(1.0/16.0,0))? Which would take the pixel at 1,0. \$\endgroup\$ – test Jul 5 '16 at 21:44
  • \$\begingroup\$ Do I need to be concerned about how many colors are in the source image? I am using a tileset where I draw a specific grayscale tile which I've mapped out the indexes of. Those indexes should correspond to indexes in the color map. In that same tileset can be any other non-grayscale colors. \$\endgroup\$ – test Jul 5 '16 at 21:54
  • \$\begingroup\$ I am not sure I follow your first comment; perhaps you could use the Game Development Chat to explain in more detail than fits here? For your second comment, it gets trickier if you want to have "non-palette" colors in the index image, the simplest way to do it is probably define yourself a value range below/above which you don't do the secondary lookup and instead pass the color through directly. \$\endgroup\$ – user1430 Jul 5 '16 at 22:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.