-2
\$\begingroup\$

There are sprites, with certain pixels being bright pink, and a shader dyes these pink or grayscale pixels to a custom color determined by the player. For example, a character looks normal except for his karate belt, which is dyed based on the level of the player (a variable outside the shader which changes the belt's color throughout the game).

I am looking to not have to use another texture as a mask, because that is a lot of extra work for all the animation frames of every character.

Something like this:

originalFaceColor --> newFaceColor

originalShirtColor --> newShirtColor

originalHairColor --> newHairColor

I know how to do this in code to edit the texture and create a new one:

getPixel(); if(color) setPixel(newColor);

but would prefer to use a shader instead because all characters will share the exact same image, but I'd like each character to have unique colors.

\$\endgroup\$
  • \$\begingroup\$ I assume Unity's shader is different than GLSL, so I cannot simply copy over the method and have it "just work the same way". I also have no idea how to pass a parameter to a shader in GLSL. \$\endgroup\$ – user50286 Sep 29 '14 at 4:45
  • \$\begingroup\$ For some reason I figured this would be an easy fix. Something like GLSL code "if (pixel == color1) pixel = vec4(newColor1, 1.0); \$\endgroup\$ – user50286 Sep 29 '14 at 4:49
  • 2
    \$\begingroup\$ What is your actual question, here? Is this just "how do I write an 'if' statement?" \$\endgroup\$ – Trevor Powell Sep 29 '14 at 5:43
  • \$\begingroup\$ ..........the question is not only in the title, but pretty clear in the question. Wtf? \$\endgroup\$ – user50286 Sep 29 '14 at 6:25
  • \$\begingroup\$ Your answer is also in the question; use an 'if' statement. So what's the real question, seeing as you've already answered the question that's in the title, yourself? \$\endgroup\$ – Trevor Powell Sep 29 '14 at 11:21
0
\$\begingroup\$

You can use a simple shader for this, but I wouldn't do so, simply due to the fact that you're doing simple tinting with one color (or shades of one color) only. The Unity script above would work with some modifications, but you'll have to keep in mind that there's additional overhead/metadata in there that doesn't belong to the actual GLSL code.

What I'd do is split the texture based on tintable/non-tintable areas and then draw in two passes:

  • One pass you'll render the un-tinted part of the texture.
  • In another pass you'll render the tinted part of the texture utilizing sf::Sprite::setColor() to set the actual color.

While this might be less efficient than using a shader, you'll get far better compatibility out of this (e.g. SFML's mobile ports don't support shaders so far). In addition to that, you won't have to hardcode multiple color checks/values/swaps (which you actually won't anyway, since it's better done programmatically).

Personally, I've used this strategy in the past with the following texture:

Example texture

It's a simple sprite sheet of a guy running to the right (four frames of animation).

While the first row includes the full sprites that will be tinted, the second row contains the non-tinted areas.

To draw one of those characters, I'm using two sprites. Sprite one uses the first row of the texture and sf::Sprite::setColor() to draw colored clothes. The second sprite is drawn on top without tinting to draw the hands and face using their original colors.


If you really want to do this in a shader, I'd avoid the branching if () since that can slow down your code. Also it's quite tedious to update the code or work with multiple shades (which is a lot easier to be done with the tinting approach). So instead you could use a 1D texture 256 pixels wide. You'd just have to check a screen pixel's color and in case all three components are identical (or just red and cyan and green is 0), you'd use that value as the index in the 1D texture to get the replacement color.

\$\endgroup\$
  • \$\begingroup\$ Ah yes! That is the answer! :) One texture, but TWO sfml Sprites. Thank you. I can't believe how complicated simple color tinting of 2D gameobjects is. You're right that a shader is not the answer. For some reason, I didn't even think of Sprites. That is how SFML does things,and if only I had thought "How would SFML do it?" I could have realized the answer. Thank you again. \$\endgroup\$ – user50286 Sep 29 '14 at 17:20
  • \$\begingroup\$ Well, in my case it would be like 4-5 sprites for each character, but whatever, haha :) I've seen similar suggestions using a mask, but none suggested putting the mask in the same texture- which is a great idea. I might combine this with the idea to create the mask procedurally during runtime/load. My sprites are very tiny so performance is a non-issue there. \$\endgroup\$ – user50286 Sep 29 '14 at 17:21
  • \$\begingroup\$ As I said, using shaders is perfectly fine, you might just want to think about a way to avoid branching in your code, because that may slow down some cards significantly. \$\endgroup\$ – Mario Sep 30 '14 at 7:02
  • \$\begingroup\$ Nah, your way was significantly easier and took only a few moments to implement. I just created a tool which tears apart a texture and creates masks. Then I can choose which mask to use, if any, using Sprites and setColor(). A lot easier and quicker to do than creating a shader (especially if you have to learn GLSL), and SFML not supporting shaders with mobile is a non-contender. \$\endgroup\$ – user50286 Sep 30 '14 at 20:37

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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