Advertisement Jump to content
Sign in to follow this  
eCustic

OpenGL [Solved] Applying Color Palette to Texture

This topic is 2387 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all,

Does anyone know how I could replace the colors on a texture in run-time using OpenGL (more specifically LWJGL)? All the sprites I am loading for my game consist only of 8 shades of grey, and what I want to do is replace each of those shades of grey with a specific color which is retrieved from another 1 x 8 pixel texture. The following picture demonstrates exactly what I want to be able to do.

UvFBt.png

The reason I want to do this is to be able to reuse the same sprite for multiple things in the game. A sword for example might have the same sprite but have a different color palette applied to it depending on which material it is made of.

I've implemented a system for this once in Java2D, which I obviously can't use now that I'm using OpenGL, but I was wondering whether this could be achieved with shaders or something. Please note that in this case I can't simply use color tinting or changing the hue, since I want to be able to control the specific color for each shade of grey (so that shadows can be bluish/purplish while highlights can be more yellow/orange etc.). In my Java2D game I had implemented it so that I had 4 channels on each sprite, grey, red, green and blue, and each channel could have its own color palette applied.

Thanks in advance. smile.png Edited by eCustic

Share this post


Link to post
Share on other sites
Advertisement
You can do this with a texture lookup in a shader. Create a bunch of 1d texture containing your palettes. When you're drawing something bind the appropriate palette texture to another texture unit. Do a texture lookup on the greyscale texture to get a 0...1 result, then do a lookup on the palette texture using that result to get the final colour.

You can fine-tune the behaviour by e.g. selecting a GL_NEAREST sampling mode.

That's one way of doing it; there are others, such as loading your palette into an array of uniforms (or using a UBO) and using the greyscale lookup * 255 as an index into that.

Share this post


Link to post
Share on other sites
This is called gradient mapping, L4D2 used it to create a great variation of zombies. Take a look at their publication Shading a Bigger, Better Sequel: Techniques in Left 4 Dead 2 from valve, which you can download here.

Share this post


Link to post
Share on other sites
Thanks guys! I've made it work and thought I'd post the relevant code here to help anyone else trying to do this.

So I did basically exactly what mhagain suggested. I load both my sprite and palette as textures (both 2D textures for now) and then I have a fragment shader which gets the brightness value from my sprite and returns a color from the palette based on that value.

Fragment Shader:

uniform sampler2D texture;
uniform sampler2D palette;
void main()
{
vec4 textureColor = texture2D(texture, gl_TexCoord[0].xy).rgba;
vec3 paletteColor = texture2D(palette, vec2(textureColor.r, 0)).rgb;
gl_FragColor = vec4(paletteColor.r, paletteColor.g, paletteColor.b, textureColor.a);
}


In the above code only the red value of the texture color is used to look up the color in the palette. The reason for this is that the sprite is greyscaled, meaning that the R,G and B values are equal, and I felt it would be a waste to calculate the average (brightness) since it would give the same value. The gl_TexCoord[0] is set in the vertex shader which is quite simple as well.

Vertex Shader:

void main() {
gl_Position = ftransform();
gl_TexCoord[0] = gl_MultiTexCoord0;
}


Lastly I'll just include the Java code for actually using these shaders (excluding the loading/compiling part):


int paletteLocation = GL20.glGetUniformLocation(shaderProgram, "palette");
GL20.glUniform1i(paletteLocation, 1);
GL13.glActiveTexture(GL13.GL_TEXTURE1);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, palette.getTextureID());


int textureLocation = GL20.glGetUniformLocation(shaderProgram, "texture");
GL20.glUniform1i(textureLocation, 0);
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture.getTextureID());

GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(1, 0);
GL11.glVertex2f(64, 0);
GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(64, 128);
GL11.glTexCoord2f(0, 1);
GL11.glVertex2f(0, 128);
GL11.glEnd();


Just to summarize the above code: I first bind the palette texture to GL_TEXTURE1 and enable the shader to reference it using the variable name "palette". Then I do the same thing for the sprite texture except I use GL_TEXTURE0 and the variable name "texture". I then simply draw a quad with the sprite texture in immediate mode.

So thanks again for the help and I hope that this helps anyone else with a similar issue. happy.png

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!