Jump to content

  • Log In with Google      Sign In   
  • Create Account

[Solved] Applying Color Palette to Texture

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 eCustic   Members   -  Reputation: 112


Posted 06 July 2012 - 08:17 PM

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.

Posted Image

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. Posted Image

Edited by eCustic, 11 July 2012 - 04:49 AM.


#2 mhagain   Crossbones+   -  Reputation: 10241


Posted 06 July 2012 - 08:25 PM

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.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.

#3 Ashaman73   Crossbones+   -  Reputation: 12311


Posted 07 July 2012 - 04:02 AM

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.



Gnoblins: Website - Facebook - Twitter - Youtube - Steam Greenlit - IndieDB - Gamedev Log

#4 eCustic   Members   -  Reputation: 112


Posted 11 July 2012 - 04:47 AM

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);
   GL11.glBindTexture(GL11.GL_TEXTURE_2D, palette.getTextureID());

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

   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);

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. Posted Image

Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.