用渐变颜色动态填充数组c++
Fill array dynamicly with gradient color c++
我想要做的是用彩虹渐变填充数组。该数组应包含 256 个条目,并填充了颜色的十六进制值。
喜欢:
array[0] = 0xFF0000 //red
...
array[85] = 0xFFA200 //orange
...
array[170] = 0x00AF0F //green
...
array[255] = 0xAE00FF //purple
因为我不想将所有 256 种颜色 "by hand" 分配给数组,所以我正在为此寻找一种动态方法。它不一定需要是上面显示的 ranbow。图片仅供演示。
关于如何在(最好)简短的代码片段中避免几个嵌套的 for 循环做这样的事情有什么建议吗?
做你想做的事情的一种方法是从它们的开始值到它们的结束值插入每个组件颜色 (RGB)。这意味着使用尽可能相同大小的步骤。
要获得 RGB 分量,需要进行一些位操作。此代码为您提供完整颜色的三种分量颜色 fullColour
:
std::array<float, 3> colourRGB;
for(unsigned i = 0; i<3; ++i) {
colourRGB[i] = (fullColour & (0xFF << (i*8))) >> (i*8);
您使用它来获取开始和结束颜色的 RGB 数组(例如,对于您示例中的红橙色范围,这将是 0xFF0000
和 0xFFA200
的 RGB 分解).对于每个组件,您然后计算出 'fade' 中每个步骤所需的步长。这是由该组件的总变化除以总步骤数得出的。对于红橙色示例,红色分量的步长因此为 1.91(因为您有 86 步并且总变化为 (0xA2
- 0x00
,或十进制为 162,得到 162/86 =1.91)。其他组件的步长为零,因为它们不会改变。
然后您可以迭代这些步骤,在每个步骤中添加另一个步长并四舍五入以获得每个组件的新值。例如,在步骤 s
:
red[s] = startingRed + ((float)s * stepSizeRed)
要将您的 rgb 值重新组合成全彩色,只需再次应用一些位操作:
fullColour[s] = 0;
for(unsigned i=0; i<3; ++i)
fullColour[s] += rgbComponent[s][i] << (i*8);
这种方法在任意数量的步骤中从任何开始到任何结束颜色产生所需的 'fade'。
我们想从:
red -> yellow
yellow -> green
green -> cyan
cyan -> blue
blue -> magenta
magenta -> red
在每一遍中,red
、green
、blue
分量之一总是 0
,第二个是 255
,第三个在 0
和 255
之间增加或减少。
换句话说:
{255, 0, 0} -> {255, 255, 0} grn increases to 255
{255, 255, 0} -> { 0, 255, 0} red decreases to 0
{0 , 255, 0} -> { 0, 255, 255} blu increases to 255
{0 , 255, 255} -> { 0, 0, 255} grn decreases to 0
{0 , 0, 255} -> {255, 0, 255} red increases to 255
{255, 0, 255} -> {255, 0, 0} blu decreases to 0
这会产生 256 * 6 种颜色,我们可能不需要所有这些颜色,因此必须对其进行归一化。这可以通过以下代码完成:
//input: ratio is between 0.0 to 1.0
//output: rgb color
uint32_t rgb(double ratio)
{
//we want to normalize ratio so that it fits in to 6 regions
//where each region is 256 units long
int normalized = int(ratio * 256 * 6);
//find the region for this position
int region = normalized / 256;
//find the distance to the start of the closest region
int x = normalized % 256;
uint8_t r = 0, g = 0, b = 0;
switch (region)
{
case 0: r = 255; g = 0; b = 0; g += x; break;
case 1: r = 255; g = 255; b = 0; r -= x; break;
case 2: r = 0; g = 255; b = 0; b += x; break;
case 3: r = 0; g = 255; b = 255; g -= x; break;
case 4: r = 0; g = 0; b = 255; r += x; break;
case 5: r = 255; g = 0; b = 255; b -= x; break;
}
return r + (g << 8) + (b << 16);
}
用法:
double range = 500.0;
for (double i = 0; i < range; i++)
{
uint32_t color = rgb(i / range);
...
}
输出:
我想要做的是用彩虹渐变填充数组。该数组应包含 256 个条目,并填充了颜色的十六进制值。
喜欢:
array[0] = 0xFF0000 //red
...
array[85] = 0xFFA200 //orange
...
array[170] = 0x00AF0F //green
...
array[255] = 0xAE00FF //purple
因为我不想将所有 256 种颜色 "by hand" 分配给数组,所以我正在为此寻找一种动态方法。它不一定需要是上面显示的 ranbow。图片仅供演示。
关于如何在(最好)简短的代码片段中避免几个嵌套的 for 循环做这样的事情有什么建议吗?
做你想做的事情的一种方法是从它们的开始值到它们的结束值插入每个组件颜色 (RGB)。这意味着使用尽可能相同大小的步骤。
要获得 RGB 分量,需要进行一些位操作。此代码为您提供完整颜色的三种分量颜色 fullColour
:
std::array<float, 3> colourRGB;
for(unsigned i = 0; i<3; ++i) {
colourRGB[i] = (fullColour & (0xFF << (i*8))) >> (i*8);
您使用它来获取开始和结束颜色的 RGB 数组(例如,对于您示例中的红橙色范围,这将是 0xFF0000
和 0xFFA200
的 RGB 分解).对于每个组件,您然后计算出 'fade' 中每个步骤所需的步长。这是由该组件的总变化除以总步骤数得出的。对于红橙色示例,红色分量的步长因此为 1.91(因为您有 86 步并且总变化为 (0xA2
- 0x00
,或十进制为 162,得到 162/86 =1.91)。其他组件的步长为零,因为它们不会改变。
然后您可以迭代这些步骤,在每个步骤中添加另一个步长并四舍五入以获得每个组件的新值。例如,在步骤 s
:
red[s] = startingRed + ((float)s * stepSizeRed)
要将您的 rgb 值重新组合成全彩色,只需再次应用一些位操作:
fullColour[s] = 0;
for(unsigned i=0; i<3; ++i)
fullColour[s] += rgbComponent[s][i] << (i*8);
这种方法在任意数量的步骤中从任何开始到任何结束颜色产生所需的 'fade'。
我们想从:
red -> yellow
yellow -> green
green -> cyan
cyan -> blue
blue -> magenta
magenta -> red
在每一遍中,red
、green
、blue
分量之一总是 0
,第二个是 255
,第三个在 0
和 255
之间增加或减少。
换句话说:
{255, 0, 0} -> {255, 255, 0} grn increases to 255
{255, 255, 0} -> { 0, 255, 0} red decreases to 0
{0 , 255, 0} -> { 0, 255, 255} blu increases to 255
{0 , 255, 255} -> { 0, 0, 255} grn decreases to 0
{0 , 0, 255} -> {255, 0, 255} red increases to 255
{255, 0, 255} -> {255, 0, 0} blu decreases to 0
这会产生 256 * 6 种颜色,我们可能不需要所有这些颜色,因此必须对其进行归一化。这可以通过以下代码完成:
//input: ratio is between 0.0 to 1.0
//output: rgb color
uint32_t rgb(double ratio)
{
//we want to normalize ratio so that it fits in to 6 regions
//where each region is 256 units long
int normalized = int(ratio * 256 * 6);
//find the region for this position
int region = normalized / 256;
//find the distance to the start of the closest region
int x = normalized % 256;
uint8_t r = 0, g = 0, b = 0;
switch (region)
{
case 0: r = 255; g = 0; b = 0; g += x; break;
case 1: r = 255; g = 255; b = 0; r -= x; break;
case 2: r = 0; g = 255; b = 0; b += x; break;
case 3: r = 0; g = 255; b = 255; g -= x; break;
case 4: r = 0; g = 0; b = 255; r += x; break;
case 5: r = 255; g = 0; b = 255; b -= x; break;
}
return r + (g << 8) + (b << 16);
}
用法:
double range = 500.0;
for (double i = 0; i < range; i++)
{
uint32_t color = rgb(i / range);
...
}
输出: