Hi all,
So I’m trying to get palette swapping working in my engine, and I’m having trouble with the shader.
My approach is this:
- I process a PNG image into both a 1-Dimensional palette image with each unique color, as well as an “indexed” version of the image where the R-Channel of the image corresponds to index of that color.
Example:
The palette:
The indexed image:
The expected result:
- In my shader, I pass in both the “SpriteTexture” (The “indexed” image referenced above), and the “PaletteTexture” (The palette image referencd above), and at each pixel of the Sprite Texture, I get the value of the R channel from this pixel, and use it as an index on the Palette Texture to get the color at that location. Or I guess I should say theoretically, because it’s not working.
What I end up getting looks like this:
Kind of just looks like the mapping is just off by a bit, but what’s strange is that most of the colors in that image on the right don’t actually exist in the original palette. I also should note that I have manually confirmed that the mapping is correct by creating a Texture2D and remapping the color data manually in code.
I’ve tried using the PaletteTexture object as a Texture1D and just passing in “color.r”. I’ve tried it as a Texture2D and pass in either “float2(color.r, 0)” or “int2(color.r, 0)” but to no avail.
Below is the entirety of the shader code:
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif
bool isActive;
Texture2D SpriteTexture;
sampler2D SpriteTextureSampler = sampler_state
{
Texture = <SpriteTexture>;
};
Texture1D PaletteTexture;
sampler1D PaletteTextureSampler = sampler_state
{
Texture = <PaletteTexture>;
};
int PaletteTextureWidth;
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
float2 TextureCoordinates : TEXCOORD0;
};
float4 MainPS(VertexShaderOutput input) : COLOR
{
float4 color = tex2D(SpriteTextureSampler, input.TextureCoordinates);
if (isActive && color.a > 0)
{
color = tex1D(PaletteTextureSampler, color.r);
}
return color;
}
technique SpriteDrawing
{
pass P0
{
PixelShader = compile PS_SHADERMODEL MainPS();
}
};
What I find particularly bizarre is that if I make changes to this which are syntactically different but functionally identical.
E.g., If I the index to a variable and passing that variable in to the tex1D constructor vs. putting the expression itself in the constructor), I get totally different behavior.
int index = color.r;
color = tex1D(PaletteTextureSampler, index);
^ Once again, the color on the right is not in the original palette.
Thanks for any and all help.
EDIT: Thought I’d add a small snippet of the C# code as well:
paletteEffect.IsActive().SetValue(activePalette != null);
paletteEffect.Parameters["SpriteTexture"].SetValue(novaFaceIndexed.OutputTexture);
paletteEffect.Parameters["PaletteTexture"].SetValue(activePalette);
paletteEffect.CurrentTechnique.Passes[0].Apply();
spriteBatch.DrawImage2D(novaFaceIndexed);