Paint me a Rainbow

2019-01-22 03:06发布

How would you go about making a range of RGB colours evenly spaced over the spectral colour range? So as to look like a real rainbow.

8条回答
Deceive 欺骗
2楼-- · 2019-01-22 03:32

The other solutions require rather large amounts of code and conditional branching, which makes them unsuitable for GPUs. I recently arrived at the following magically simple formula in GLSL. It's essentially the same in OpenCL:

vec3 HueToRGB(float hue) {
  vec3 h = vec3(hue, hue + 1.0/3.0, hue + 2.0/3.0);
  return clamp(6.0 * abs(h - floor(h) - 0.5) - 1.0, 0.0, 1.0);
}

This will give you a rainbow color that corresponds to the given hue value in linear RGB. To use in an image, convert to sRGB and then multiply by 255.

Here is a C++ version:

float clamp(float value, float low, float high) {
  return value < low ? low : (value > high ? high : value);
}
void HueToRGB(float hue, float *rgb) {
  rgb[0] = hue;
  rgb[1] = hue + 1.f/3.f;
  rgb[2] = hue + 2.f/3.f;
  for (unsigned i = 0; i < 3; ++i) {
    rgb[i] = clamp(6.0f * fabsf(rgb[i] - floorf(rgb[i]) - 0.5f) - 1.f, 0.f, 1.f);
  }
}

The key here is to realize that the graph of each of the R, G, B coordinates in function of the hue value is a clamped value of a periodic triangle function, and that can be obtained as the absolute value of a sawtooth function, x - floor(x).

查看更多
疯言疯语
3楼-- · 2019-01-22 03:38

The simplest approach is to do a linear interpolation (in RGB) between each consecutive pair in this sequence:

  • #ff0000 red
  • #ffff00 yellow
  • #00ff00 green
  • #00ffff cyan
  • #0000ff blue
  • #ff00ff magenta
  • #ff0000 back to red

This should get you pretty much the same result as sweeping through the hue values in HSV or HSL, but lets you work directly in RGB. Note that only one component changes for each interpolation, which simplifies things. Here's a Python implementation:

def rainbow():
  r, g, b = 255, 0, 0
  for g in range(256):
    yield r, g, b
  for r in range(255, -1, -1):
    yield r, g, b
  for b in range(256):
    yield r, g, b
  for g in range(255, -1, -1):
    yield r, g, b
  for r in range(256):
    yield r, g, b
  for b in range(255, -1, -1):
    yield r, g, b
查看更多
登录 后发表回答