- Home /
How to swap out RGB colors of a sprite using ShaderGraph? (Like in Among Us)
So I have noticed that the player sprites in Among Us use red, green and blue colors and somehow change them with the player color. As someone who has just gotten into shaders because of this specific reason, I really want to know how to achieve a clear output. The original sprite
I've tried 2 ways to change the colors.
(3 is an adjustment on shader 2)
1) First I tried using the Replace Color Node but that caused some pixel inaccuracies and a non-filtered image. The image looks pixelated. I don't know a way to make it look smoother so if there's one, please let me know. When looking at them here, it might look OK but in the game it's really noticable. NOTE: The reason for the outlined shadow is because of an unnecessary calculation I did, I fixed it now. Edit: Using this method, it's also impossible to choose every single color because sometimes the chosen color gets replaced by the shader so that's kind of unfortunate.
2) Then by seperating the RGB channels and multiplying them with the respective colors, I got this smooth image. However, since I change the overall RGB value, the white/gray parts seem to also change color, whereas they should remain white/gray.
3) And for the 3rd image; I added the RGB values together BEFORE changing colors and multiplied the result with the 2nd image's result. This fixed the white part on the head/helmet but the shadow remains colored. It's also obvious that some color values have changed to be darker.
I'm a bit curious on getting a clear result since this method of using red, green, blue and changing them via shader is an absolute time saver. Since this is the actual sprite used in the game, I'm not able to change it. I just want to know how it was achieved. Any help would be most appreciated.
Welp, I guess I found something. For anyone wondering, I went with the Replace Color Node. At first I've tried increasing the "range" parameter and left "fuzziness" at 0. Now I tried increasing fuzziness and leaving range mostly same, I got a nice result. It has few unchanged pixels but they're not noticable from a distance.
EDIT: It looks really bad with different colors and so I have to choose every bleeding color and change them to whatever the value should be. Which, obviously is not how I'm supposed to do it.
Hey I need your help so I have changed the player sprite to my player in game but now since their is a shader In game that forces you to use a color you pick my sprite color look weird so if I choose green then my sprite will look green. I’m wondering is their a way I can just remove the shader or replace one do the shader colors to just plain ??
Will you give me the image of what your solved one looks like?
Answer by Sspyrshlsx · Oct 28, 2020 at 05:19 PM
Hooray! i found a neat way to make it work just perfectly. So I've used the 2nd shader I mentioned above. Basically, it uses the Red, Green and Blue channels individually. Then, it uses a Multiply Node to multiply each channel with the desired colors. Lastly, it adds them together and gives the result. However, doing ONLY this makes the white/gray parts of the image also change color. You might want to keep some colors as they are.
So here's the solution I came up with. First, get the channels which include the color you want to keep. Then, use a Color Mask Node to get the specific part you want to keep. Do this multiple times if you have multiple colors and add the results together. Next up, you want to subtract the masked colors from each R/G/B channel BEFORE coloring them. This makes sure that you don't color the masked parts. Then, add the RGB channels together as usual. Last, add the masked colors to the result. This should hopefully give a clean result. I can post an image of the shader graph if anyone is interested, but it looks like spaghetti so... yeah. Though I'm sure it's easy to understand. I'm quite a beginner so this is definitely not the most efficient code but it does the job. Also, it works with different sprites/animations as well since it's a shader.
Hi, I am really interested in this stuff and I am new to Shader Graph. Could you please share your shader graph image?
Thanks so much!!
Hi, I am trying to use the same shader settings you have but can't seem to wrap my head around it may you send a picture of your settings so I can have the same effect?
Sure, here's the graph. Though it's kinda spaghetti so apologies on that lol. I$$anonymous$$PORTANT: This only works with sprites that include ONLY certain colors. Some colors will not be rendered correctly. This seems to work fine with all sorts of player sprites or anything you see in the game files that are seperated to RGB channels.
BASICS. First of all, the basic theory is that you take each channel and multiply them with a color. This on its own works just fine until you add new colors to your sprite. Also keep in $$anonymous$$d that black will also work fine because multiplying zero with anything equals zero.
EXCLUDING SO$$anonymous$$E COLORS. To get clean results, we need to use a Color $$anonymous$$ask node to mask out certain colors. Then, we multiply that mask's output with the color to get the result colored. Here are all the colors I could find in all the sprites of the game: White, a specific shade of white and a specific shade of gray. Now the reason the shades are "specific" is because unfortunately, we can't just mask white and expect all shades to also be masked. We need to manually mask all shades of that color. So we use multiple color masks and combine the result.
WHERE THINGS GET CO$$anonymous$$PLICATED. Remember the dead body sprite with a huge bone sticking out of it? That sprite uses 2 shades of white. We need to mask both shades as mentioned above. But there is one tiny problem. The colors are too similar, so if we mask out both, the masks overlap. So we mask only one color (which in this case is the shade of white) and add the other shade later on to the result. This should give a clean result.
I guess I'm just going to share the graph itself rather than trying to combine some crappy images. Hope it's understandable. You can modify the shader to your liking for your own sprites, keeping in $$anonymous$$d what I mentioned above. It certainly isn't the best way for dealing with multiple player colors in my opinion, but it works fine for a game like Among Us. I also placed some notes here and there so it should be easier to understand hopefully. I also included some images from the game that might help you test the shader.
Here are the files on Google Drive: (https://drive.google.com/file/d/1ZcztV6Js1EECZ-BliymG-Sp3c2qdrDvq/view?usp=sharing) Also make sure that your project has URP/HDRP enabled.
Hi, Wow, your work is really fantastic. I imported it to Unity and it worked perfectly. Also, your note makes the graph understandable. In addition to this, I have been trying to figure out how the shadow can cut off the player.
I suppose they use Light 2D, Shadow Caster 2D for the shadow. I know it is not relevant to the topic but if you have any idea on this, I would be very grateful.
I'm glad to see it helped! Also for lighting pretty sure they don't use the URP 2d lighting components, and they aren't really ideal for something like this. (They didn't even exist during Among Us' development!) If you noticed, the player gets masked out in the shadow but the rest of the room is still visible. They have an image that renders in front of everything and they handle lights on that object. Here are some resources I think should help.
For casting shadows, you should be casting rays. Here's a great page: https://www.redblobgames.com/articles/visibility/
A youtube video on recreating among us. But I don't know if placing hundreds of squares around the map is ideal, so you might want to find a better solution. Still, might help out: https://www.youtube.com/watch?v=24kZ9ZX1xvU
A really good research breaking down some development tricks, innersloth also retweeted the video on their twitter: https://www.youtube.com/watch?v=N795ZNruID$$anonymous$$&feature=youtu.be
Answer by unity_npxNcRagf5BCxA · Oct 28, 2020 at 01:55 PM
I am not the best at dealing with the shader graph but, I may be able to help you with this dilemma...
Since you already have a good system with number 3, you could have the character be on a different sprite than the shadow, thus keeping the shadow the same colour. Then have the shadow follow the character, this could be useful with animations to where you don't have to worry about the updating the shadow every frame used.
Like I did say, I don't know much about unity's shader system and there may be way better options than the way I said. Hopefully, you have found some use in what I had to say.
Yeah, as I mentioned, if I've made the sprites I'd definetely make the shadow on a different image but this is the source image I have. I just wanted to know how to get a perfect result with it since in Among Us the player colors are just perfect. And, I know that the game is also made with Unity even though it doesn't really matter much.
Answer by Irishbruse · Dec 16, 2020 at 12:41 PM
If you prefer to use code then use something like this
float allChannels = In.r+In.b+In.g;
float mask=min(min(In.b,In.g),allChannels);
float brightMask = In.r-mask;
float shadowMask = In.b-mask;
float visorMask = In.g-mask;
float4 result;
result += brightMask * Bright_Color;
result += shadowMask * Shadow_Color;
result += visorMask * Visor_Color;
result += mask;
result.a = In.a;
return result;
Your answer
Follow this Question
Related Questions
Access properties of Material through script. 3 Answers
UI Triangle Color picker 0 Answers