Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

C# Color detection issue

Discussion in 'Scripting' started by HK_PHANTOM, Aug 9, 2018.

  1. HK_PHANTOM

    HK_PHANTOM

    Joined:
    Jul 12, 2018
    Posts:
    11
    Hi all, I've got a problem I've been stuck with for a good few hours now.
    I've got a script that changes object A's color for example:

    if (Input.GetKeyDown(KeyCode.A))
    {
    gameObject.GetComponent<Renderer>().material.color = Color.red;
    }

    This works just fine, however when I try to detect object A's color and compare it to object B's color it doesn't seem to work. The code I'm using for the detection is:

    if(this.gameObject.GetComponent<Renderer>().material.color == objectAMat.color)
    {
    Debug.Log("Testing");
    }

    Where objectAMat is a public material (Object A's material). This script lies on object B.

    Note that if I manually change object A's material color, the code works fine and displays the Debug.Log.

    So my guess is that the code isn't actually changing the material color of object A or something, any help here?
     
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Colours are a series of three floats. So its very unlikely any two colours will be identical. Instead you want to test if the colors are close enough. Distance is a pretty decent way to do this.
     
  3. HK_PHANTOM

    HK_PHANTOM

    Joined:
    Jul 12, 2018
    Posts:
    11
    Well I have already tried making sure all the Hex numbers are identical. How would I go about checking distance of the colors?
     
  4. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    I would say it isn't a good idea to compare colors for equality. I don't know what you are trying to achieve, but most probably this is a bad approach. Use some helper property, for instance enums and compare these.

    EDIT: For the case that you really need to compare colors, use something like this:
    Code (CSharp):
    1. private bool AreApproximatelyEqual(Color color1, Color color2, float tolerance = 0.00001f)
    2. {
    3.     return Vector4.SqrMagnitude((Vector4)color1 - (Vector4)color2) < tolerance;
    4. }
    Anyways, you should print out the values of both colors. If they differ too much, your problem lies somewhere else.
     
    Last edited: Aug 9, 2018
  5. Lyker

    Lyker

    Joined:
    Feb 27, 2013
    Posts:
    60
    Quite a while back I wanted to learn about genetic algorithms and I used colors for this. I had a set of randomized colors and picked only the best ones; this means I had to know how "similar" colors are. I looked this up on google and found a way via the CIELAB76 method. This does mean that you need 2 colors in the CIELAB color space.

    Long story short: I found some code somewhere and combined with these wiki pages I created the following:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CIELabColor
    5. {
    6.     public float l;
    7.     public float a;
    8.     public float b;
    9.  
    10.     public static CIELabColor FromXYZ(XYZColor color)
    11.     {
    12.         CIELabColor result = new CIELabColor();
    13.  
    14.         float x = color.x / 95.047f;
    15.         float y = color.y / 100f;
    16.         float z = color.z / 108.883f;
    17.  
    18.         if (x > 0.008856f)
    19.         {
    20.             x = Mathf.Pow(x, 1f / 3f);
    21.         }
    22.         else
    23.         {
    24.             x = (7.787f * x) + (16f / 116f);
    25.         }
    26.  
    27.         if (y > 0.008856f)
    28.         {
    29.             y = Mathf.Pow(y, 1f / 3f);
    30.         }
    31.         else
    32.         {
    33.             y = (7.787f * y) + (16f / 116f);
    34.         }
    35.  
    36.         if (z > 0.008856f)
    37.         {
    38.             z = Mathf.Pow(z, 1f / 3f);
    39.         }
    40.         else
    41.         {
    42.             z = (7.787f * z) + (16f / 116f);
    43.         }
    44.  
    45.         result.l = (116f * y) - 16f;
    46.         result.a = 500f * (x - y);
    47.         result.b = 200f * (y - z);
    48.  
    49.         return result;
    50.     }
    51.  
    52.     public float DistanceTo(CIELabColor color)
    53.     {
    54.         float deltaL = Mathf.Pow(color.l - l, 2f);
    55.         float deltaA = Mathf.Pow(color.a - a, 2f);
    56.         float deltaB = Mathf.Pow(color.b - b, 2f);
    57.         float delta = Mathf.Sqrt(deltaL + deltaA + deltaB);
    58.  
    59.         return delta;
    60.     }
    61. }
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class XYZColor
    5. {
    6.     public float x;
    7.     public float y;
    8.     public float z;
    9.  
    10.     public static XYZColor FromColor(Color color)
    11.     {
    12.         XYZColor result = new XYZColor();
    13.  
    14.         float r = color.r;// / 255f;
    15.         float g = color.g;// / 255f;
    16.         float b = color.b;// / 255f;
    17.  
    18.         if (r > 0.04045f)
    19.         {
    20.             r = Mathf.Pow((r + 0.055f) / 1.055f, 2.4f);
    21.         }
    22.         else
    23.         {
    24.             r = r / 12.92f;
    25.         }
    26.  
    27.         if (g > 0.04045f)
    28.         {
    29.             g = Mathf.Pow((g + 0.055f) / 1.055f, 2.4f);
    30.         }
    31.         else
    32.         {
    33.             g = g / 12.92f;
    34.         }
    35.  
    36.         if (b > 0.04045f)
    37.         {
    38.             b = Mathf.Pow((b + 0.055f) / 1.055f, 2.4f);
    39.         }
    40.         else
    41.         {
    42.             b = b / 12.92f;
    43.         }
    44.  
    45.         r *= 100f;
    46.         g *= 100f;
    47.         b *= 100f;
    48.  
    49.         result.x = r * 0.4124f + g * 0.3576f + b * 0.1805f;
    50.         result.y = r * 0.2126f + g * 0.7152f + b * 0.0722f;
    51.         result.z = r * 0.0193f + g * 0.1192f + b * 0.9505f;
    52.  
    53.         return result;
    54.     }
    55. }
    I simply copied the math so I don't know how it works, but you can use the CIELabColor.DistanceTo() to calculate a difference in color. The reason there are 2 colors classes here is because you had to convert from RGB color to XYZ color to CIELAB color. The usage of these scripts is as follows:

    Code (CSharp):
    1. Color rgb = new Color(Random.value, Random.value, Random.value);
    2. XYZColor xyz = XYZColor.FromColor(rgb);
    3. CIELabColor lab = CIELabColor.FromXYZ(xyz);
    4.  
    5. Color targetRgb = new Color(Random.value, Random.value, Random.value);
    6. XYZColor targetXyz = XYZColor.FromColor(targetRgb);
    7. CIELabColor targetLab = CIELabColor.FromXYZ(targetXyz);
    8.  
    9. float delta = lab.DistanceTo(targetLab);
    10. Debug.Log(delta);
    A delta of 0 means the colors are exactly right, so you'd have to play with some tolerance to see what fits your needs. To see it in action, here is an example of what I made back then. The goal is to get all the colors at the bottom to match the single color at the top. Each time the bottom colors refresh, the best ones are picked using this approach and may breed offspring and the worst ones simply get replaced by named offspring.

    https://gyazo.com/2d7e8b425467acdb4536318836b9037d
     
  6. HK_PHANTOM

    HK_PHANTOM

    Joined:
    Jul 12, 2018
    Posts:
    11
    Thanks for the information. I've ended up changing my code a bit to make an array of colored materials and it is detecting them better now. I think the problem was I was using a script to change the color of one material and it didn't like that and could only tell that it was the original material color. Thanks everyone! :D
     
  7. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    RBG colour is a colour space set up to measure colour in terms of hardware representation. Each value corresponds directly to the the intensity of light sent to the screen. LAB colour space is set up to measure colour in a similar fashion to the human eye. That means that two colours the same LAB distance apart should appear to be different by the same amount.

    Technically speaking LAB is an absolute colour space. So you actually need to calibrate your screen in order to find the true conversion factors from your screen into LAB space. But that really doesn't matter for game dev purposes. (That said, I wouldn't even bother going into LAB space for games at all. RBG distance should be fine for most purposes).

    LAB isn't perfect, a delta e of <1 across most of the range is considered the same colour to human eyes, but there are some places (bight green) where a delta e of 0.5 still looks obviously wrong. And when you get to blacks you can often be several units out without noticing.

    (Sorry if nobody cared. Colours are my day job, so I get paid to know this stuff.)
     
  8. Lyker

    Lyker

    Joined:
    Feb 27, 2013
    Posts:
    60
    I cared, I never knew. :)

    Interesting stuff. If you put it that way, a simple RGB check should definitely be good enough then.
     
    Kiwasi likes this.
  9. bogheorghiu

    bogheorghiu

    Joined:
    Oct 14, 2018
    Posts:
    9
    Wow! Thank you! I really needed an algorithm to detect when a color is (perceived as) white, and both RGB and HSV color spaces seemed to fail in this respect. I will definitely try this one out.