• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by esitoinatteso · Feb 12, 2014 at 11:24 AM · shadercolorchangetextureing

Choose color/palette swap?

Hi pals! I've been wandering throughout a lot of links and webpages all talking almost about what I'd like to do, but I couldn't understand none of them. As usual, not only I admit my knowledge of the argument itself is pretty lacking, but also the inability to have a talk with someone who can actually explain it to me in a more intelligible way, you know, it's not really helpful.

So what's this all about? I'm about to color some drawings with which I plan to make a character in a 2d videogame. I'll import them in Unity as one big atlas. Correct me if I'm wrong, when I do this the original atlas is considered to be a texture, while what I trim from it is a sprite, right? Well then, what I'd like to do is to let players choose from a 255 RGB ramp the color they'd like to represent with a certain portion of the sprite.

In other words... when I'm in Photoshop and want to change an image's colors I just press Command+U and a wonderful window pops up complete with a set of HSL/HSV ramps. To prevent all colors to change I could do many things, usually I just keep different colors on different layers and that's it.

Let's pretend I already know how to make a 255 RGB ramp and display it, then what should I do to pick a color on my original texture and change it to another one? Maybe one that I've just selected with, say, my mouse from that ramp? This transformation will apply to all the sprites derived from that texture? Why should I need to color my texture in grayscale... I mean, different colors are just different, what's the point in having them depicted with a certain shade of gray in the first place? Does what I'm asking make sense to you?

Plus, is this thing also known as palette swapping? I know those are a bunch of topics and I'm really sorry about it, but I have to understand this thing as soon as I can and usually the faster way I know of is asking to you guys.

Thanks and sorry for my english!

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by Scribe · Feb 12, 2014 at 07:31 PM

What the hell does that code do?!...

  1. Firstly we must somehow fetch the sprite that was clicked on. To do this I use a raycast from the camera to the mouse position. This requires your sprite to have a collider! (it can be a trigger). If there isn't a collider on your sprite gameObject the raycast will return nothing or whatever is behind your sprite.

  2. Once we have the gameObject of your sprite we must get the actual spritRender component of it using GetComponent()

  3. now that we have found a GO with a spriteRenderer that we want to recolour we must find which pixel was clicked, this is the difficult part! (or at least I don't know an easier way unless you know the shader is not effected by lighting).

  4. If the sprite is known to never be rotated then most of the code in GetPixelColor is obsolete, though if you have sprites (like arms, legs) that are being rotated then GetPixelColor is able to work out how far from the bottom corner of the sprite the hit point is in Cartesian coordinates that are relative to the sprites axis (this assumes that the box collider fits the sprite exactly, which is the default when you add a new box collider).

  5. Once we have the vector from the bottom corner of the collider to the hit point, relative to the sprite. We can use this information combined with the size of the piece of texture used by the sprite, to find the exact coordinate of the pixel clicked in the main texture atlas.

  6. Once we have the pixel we wish to recolour we need to find others of the same or similar colour which is done in 'RecolourTexture'

  7. RecolourTexture takes several arguments, the ones you may wish to change which are given yourself are 'buffer' which is an integer which allows all colours that are a 'distance' of buffer away from your selected colour to also be coloured (where 255 will colour everything). And 'wholeAtlas' which you should give a value of true or false.

  8. If wholeAtlas is set to true, the recolour will be applied to the entire texture atlas, if it is set to false then only the section of the texture used by the clicked sprite will be affected.

  9. The last variable you will wish to change is 'texColor' which is the colour that you are swapping in, in place of the selected colour. As your question says, 'Let's pretend I already know how to make a 255 RGB ramp and display it' you would use your result from that colour ramp and pass those values to 'texColor', as it is, you should be able to change the colour from the instpector.




    The Code




    private var screenTexture : Texture2D; private var mousePos : Vector2; private var screenColor : Color; var texColor : Color; private var colorPreview : boolean = false; var buffer : int = 20;

    function Start(){ screenTexture = new Texture2D(1, 1); }

    function RecolourTexture(point : Vector2, sprite : Sprite, buffer : int, wholeAtlas : boolean){ var texture = sprite.texture; var spriteRect = sprite.rect; var selectedColor = texture.GetPixel(point.x, point.y); var correctedBuffer = (parseFloat(buffer)/255.0); var colorDiff : float; var pixels : Color[];

      if(wholeAtlas){
             pixels = texture.GetPixels(0, 0, texture.width, texture.height);
             for(pix in pixels){
                 colorDiff = Vector4(
                     pix.r-selectedColor.r,
                     pix.g-selectedColor.g,
                     pix.b-selectedColor.b,
                     pix.a-selectedColor.a).sqrMagnitude;
                 if(colorDiff <= 4*(correctedBuffer*correctedBuffer)){
                     pix = texColor;
                 }
             }
             texture.SetPixels(0, 0, texture.width, texture.height, pixels);
             texture.Apply();
         }else{
             pixels = texture.GetPixels(spriteRect.x, spriteRect.y, spriteRect.width, spriteRect.height);
             for(pix in pixels){
                 colorDiff = Vector4(
                     pix.r-selectedColor.r,
                     pix.g-selectedColor.g,
                     pix.b-selectedColor.b,
                     pix.a-selectedColor.a).sqrMagnitude;
                 if(colorDiff <= 4*(correctedBuffer*correctedBuffer)){
                     pix = texColor;
                 }
             }
             texture.SetPixels(spriteRect.x, spriteRect.y, spriteRect.width, spriteRect.height, pixels);
             texture.Apply();
         }
     }
     
     function GetPixelColor(hit : RaycastHit, spriteRenderer : SpriteRenderer){
         var point = hit.point;
         var col = hit.collider;
         var go = col.gameObject;
         var up = go.transform.up;
         var right = go.transform.right;
         var forward = go.transform.forward;
         var hitVector = point - go.transform.position;
         var projectedVector = Vector3(
             Vector3.Project(hitVector, right).magnitude,
             Vector3.Project(hitVector, up).magnitude,
             Vector3.Project(hitVector, forward).magnitude);
         var scalerVector = Vector3(
             Vector3.Dot(right, Vector3.Project(hitVector, right))
                 /Mathf.Abs(Vector3.Dot(right, Vector3.Project(hitVector, right))),
             Vector3.Dot(up, Vector3.Project(hitVector, up))
                 /Mathf.Abs(Vector3.Dot(up, Vector3.Project(hitVector, up))),
             Vector3.Dot(forward, Vector3.Project(hitVector, forward))
                 /Mathf.Abs(Vector3.Dot(forward, Vector3.Project(hitVector, forward))));
         var realVector = Vector3.Scale(projectedVector, scalerVector)
             +(0.5*Vector3.Scale(col.size, go.transform.localScale));
             
         var sprite : Sprite = spriteRenderer.sprite;
         var spriteRect = sprite.rect;
         var pixelPos = Vector2(
             spriteRect.x + Mathf.Clamp(Mathf.Floor(realVector.x*spriteRect.width), 0, spriteRect.width),
             spriteRect.y + Mathf.Clamp(Mathf.Floor(realVector.y*spriteRect.height), 0, spriteRect.height));
         
         RecolourTexture(pixelPos, sprite, buffer, false);
     }
     
     function Update(){
         mousePos = Vector2(Mathf.Clamp(Input.mousePosition.x, 0, Screen.width-1), Mathf.Clamp(Input.mousePosition.y, 0, Screen.height-1));
         if(Input.GetButtonDown("Fire1")){
             colorPreview = true;
         }
         
         if(Input.GetButton("Fire1")){
             //colorPreview = false;
             
             var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
             var hit : RaycastHit;
             if (Physics.Raycast (ray, hit)) {
                 var col = hit.collider;
                 var spriteRenderer = col.gameObject.GetComponent.<SpriteRenderer>();
                 if(spriteRenderer != null){
                     GetPixelColor(hit, spriteRenderer);
                 }
             }
         }
         
     }
     
     function OnPostRender(){
         screenTexture = ScreenColor(mousePos, screenTexture);
     }
     
     function ScreenColor(mousePos : Vector2, tex2 : Texture2D){
         var tex = new Texture2D(1, 1);
         tex.ReadPixels(new Rect(mousePos.x, mousePos.y, 1, 1), 0, 0);
         var col = tex.GetPixel(0, 0);
         col.a = 1;
         screenColor = col;
         tex.SetPixel(0, 0, col);
         tex.Apply();
         return tex;
     }
     
     function OnGUI(){
         if(colorPreview){
             GUI.Box(Rect(mousePos.x-12,Screen.height-mousePos.y-12,14,14), "");
             GUI.DrawTexture(Rect(mousePos.x-10,Screen.height-mousePos.y-10,10,10), screenTexture);
         }
     }
    
    
    



Don't expect many people to write code like this for you, I was simply interested enough to want to find a solution myself :)

Hope that helps!

Scribe

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image esitoinatteso · Oct 21, 2014 at 09:47 PM 0
Share

Sir, I have to apologize but I never saw this reply before today and I don't know why. What you've done up there is just an amazing action of altruism ( originated by some egoistical curiosity maybe, but still selfless). I don't know what to say, except thanks a lot! Since I'm not into copy pasting things, I'm going to study that wall of code and try to understand it, I think it's the best thing I can do to honor your efforts! I owe you one!

avatar image Scribe · Oct 23, 2014 at 04:11 PM 0
Share

No worries :) I am glad you are finding it useful!

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

20 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Material doesn't have a color property '_Color' 4 Answers

Modifying a shader color dynamicly through another script 0 Answers

rendering part of a ghost when my player passes close to it 3 Answers

Changing Eye Colour (Colour only non-white parts of a texture?) 2 Answers

Color white does nothing consider mobile... really? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges