Sunday 6 January 2013

Color Wheel, HSV, HSL, RYB, RGB

In my attempt to understand Color Theory better, I decided to make a color wheel in code today. Particularly, I was interested in figuring out how to do a RYB (Red, Yellow, Blue) color wheel. Here is the result:

As you can see, I've only managed to do the RGB color wheel for this post. When I say RYB, I'm aware that it is a subtractive color model and RGB is additive. However, I also mean that Red, Yellow and Blue are equally spaced apart on the wheel, instead of the standard RGB/CMY spacing. I wanted to be able to do this because RYB is actually the natural color spectrum that our eyes can perceive as our eyes react to red, yellow and blue light, something I learned from this incredibly old but insightful video.

Due the difference between RYB and RGB spacing, it occurred to me that the probability of colors in real life is not the same as the probability of the colors we can generate from a computer.

Anyway, here are my learnings from doing this color wheel:

  1. I started off figuring out how to draw a circle or wheel in Flash through code. I knew I could not use the inbuilt drawCircle function as I needed to set the gradient of the circle manually, so I tried to use the curveTo functions in Flash after a quick refresher in control points for quadratic beziers.
  2. Once I did that, I realized that quadratic beziers formed using the corner points of a square does not form a smooth circle. I also did not know how to calculate the control points for generating a circle, given two anchor points from a circle segment. This is why you now see a polygon mesh generated instead.
  3. Flash only allows two types of gradients, LINEAR and RADIAL. I made the mistake of using RADIAL at first but quickly realized that I had to switch to LINEAR since RADIAL is used for a gradient which interpolates from inner circle to outer circle.
  4. However, LINEAR is not ideal as well since it cannot deal with segments of a circle and rather deals with boxes. You can see this effect in the demo above. The gradients interpolate smoothly on the outside edge of the wheel but it is not smooth near the middle of the wheel.
  5. When calculating the matrix for the gradients of each segment, I used an inbuilt function from the Matrix class called createGradientBox. I lost quite a bit of time figuring out this matrix. It was only after I made another Flash tool to interactively see what is happening with the matrix that I realized what was wrong. Flash automatically calculates the offsets (tx,ty), based on the box width and height that was passed in, but the way I was drawing the mesh was with a radius offset, so the solution was to set the offsets (tx,ty) manually after the matrix was created.
  6. After I managed to chop out the segments and get some gradient filling to work. I finally started looking into how to calculate the color hues. I found out on StackOverflow that there was a wiki page on HSV/HSL, which I then used to code the formulae.
  7. The HSV and HSL algorithms are similar, but I would recommend HSL since the spread is of lighter colors are more even as compared to darker colors.
  8. One of the limitations perhaps of the conversion of HSV/HSL to RGB algorithm is that it depends on dividing the hue into six main colors, namely red, yellow, green, cyan, blue, magenta. This means that when you start using a large number of sides to form a circle, you end up with a majority of segments in these primary colors.
    I made a mistake with the hue equation and got the above striked-out behaviour. It was due to the fact that I thought I should floor the h' in the equation to check which segment to apply the respective formulae. The hue now works perfectly on large number of sides.
  9. Part of the problem here is that I could not set the color for each vertex, which is also why I realized I should have made this wheel using triangles on the GPU instead of using Flash gradients. But since this is done, I leave that as a future project.
  10. In summary, if I were to redo this, I would use vertex rendering and the GPU to blend the vertex colors together. On Flash this would mean using Stage3D, or in C++, OpenGl or DirectX are both available.

No comments:

Get Adsense

Want to earn money like me? Get Google Adsense now by clicking this