Hi, I'm trying to work out how to get the gradient time (0% - 100%) from a color. Basically trying to work out this: public float GetGradientTime(Color c) - which will return a percentage where the color falls on the gradient (i.e. if the gradient was blue -> green -> red -> yellow and I passed it a colour between blue and green, it should return 15%-ish). It's pretty much the opposite of the existing method for gradients which is public Color Evaluate(float time) I'm thinking about iterating through the ColorKeys of the gradient and find the closest match to a color then return the time of that color key? Not sure if this is the best solution. Many thanks, Alex.
Colors cannot be matched directly like that. Three reasons: 1) because it's highly unlikely that your query color will be exactly equal to anything in the color gradient, 2) because Color has floating point components and these can't be matched by definition, and 3) because gradients are continuums, and you can sample them with theoretically indefinite accuracy (bound only by floating point resolution, which is ultimately 2^-27 I believe). You could round Color components to an equivalent of Color32 to narrow down the combinatorial space. Or you could introduce some error metric, and try to find the least error. But the real problem is what Gradient actually represents. Here are some older posts of mine which illustrate the problem Gradient structure Combining gradients In short, you either need to make a gradient object that is capable of working with discrete concretely defined colors, through hash codes or something similar --or-- you are supposed to make a math-friendly algorithmic solver, because scanning through a floating point continuum doesn't make any sense, performance-wise. It's not ultra-hard, but it's still non-trivial, and imo it's just too much work for something that's not really that useful.
Also note that computing color similarity is best done not with RGB, but with something like CIE Lab color space. See this: https://www.baeldung.com/cs/compute-similarity-of-colours for ways of comparing colors. See https://bitbucket.org/hasullivan/color-space/src/master/ColorSpaceConversion/Conversion.cs for code samples of how to convert between color spaces.
A quick solution is to simplify the gradient into, lets say x segments (kind of like indexed colors/custom color space) and store them into a HashSet<Color>/List<Color>/Custom optimized tree, then use Euclidean distance between the color and each segment to find the nearest match, by treating RGB components as XYZ in our imaginary coordinates system. In Unity terms we create a Vector3(R, G, B) for each of our indexed colors, calculate (squared) distances (Vector3.SqrDistance/Vector3.Distance) and choose the closest one. This should give a good approximation. Of course more segments => better precision => slower performance. Testing is needed to have a balance between precision/speed. From the top of my head, I'd say 256 is a good number to start with (precision: ~0.39%)