【发布时间】:2015-06-05 07:33:32
【问题描述】:
我目前正在尝试为我的 Mandelbrot Set explorer 创建一个颜色渐变类。
它从文本文件中读取颜色约束(RGBA8888 颜色和位置在 0 和 1 之间)并将它们添加到向量中,该向量稍后用于确定特定位置的颜色。
为了计算颜色,算法从给定位置搜索到任一侧的下一个约束,将颜色分成四个单独的通道,然后,对于每个通道,搜索两者中较低的一个并添加一部分差异等于(x-lpos)/(upos-lpos) 与较低颜色的比率。之后,通道被移位和 ORed 一起,然后以RGBA8888 无符号整数返回。 (见下面的代码。)
编辑:我完全重写了渐变类,修复了一些问题并使其更具可读性以便调试(虽然它变得慢得要命,但 -Os 或多或少会小心其中)。但是,它仍然不是应有的样子。
class Gradient { //remade, Some irrelevant methods and de-/constructors removed
private:
map<double, unsigned int> constraints;
public:
unsigned int operator[](double value) {
//Forbid out-of-range values, return black
if (value < 0 || value > 1+1E-10) return 0xff;
//Find upper and lower constraint
auto upperC = constraints.lower_bound(value);
if (upperC == constraints.end()) upperC = constraints.begin();
auto lowerC = upperC == constraints.begin() ? prev(constraints.end(), 1) : prev(upperC, 1);
if (value == lowerC->first) return lowerC->second;
double lpos = lowerC->first;
double upos = upperC->first;
if (upos < lpos) upos += 1;
//lower color channels
unsigned char lred = (lowerC->second >> 24) & 0xff;
unsigned char lgreen = (lowerC->second >> 16) & 0xff;
unsigned char lblue = (lowerC->second >> 8) & 0xff;
unsigned char lalpha = lowerC->second & 0xff;
//upper color channels
unsigned char ured = (upperC->second >> 24) & 0xff;
unsigned char ugreen = (upperC->second >> 16) & 0xff;
unsigned char ublue = (upperC->second >> 8) & 0xff;
unsigned char ualpha = upperC->second & 0xff;
unsigned char red = 0, green = 0, blue = 0, alpha = 0xff;
//Compute each channel using
// lower color + dist(lower, x)/dist(lower, upper) * diff(lower color, upper color)
if (lred < ured)
red = lred + (value - lpos)/(upos - lpos) * (ured - lred);
else red = ured + (upos - value)/(upos - lpos) * (ured - lred);
if (lgreen < ugreen)
green = lgreen + (value - lpos)/(upos - lpos) * (ugreen - green);
else green = ugreen + (upos - value)/(upos - lpos) * (ugreen - lgreen);
if (lblue < ublue)
blue = lblue + (value - lpos)/(upos - lpos) * (ublue - lblue);
else blue = ublue + (upos - value)/(upos - lpos) * (ublue - lblue);
if (lalpha < ualpha)
alpha = lalpha + (value - lpos)/(upos - lpos) * (ualpha - lalpha);
else alpha = ualpha + (upos - value)/(upos - lpos) * (ualpha - lalpha);
//Merge channels together and return
return (red << 24) | (green << 16) | (blue << 8 ) | alpha;
}
void addConstraint(unsigned int color, double position) {
constraints[position] = color;
}
};
在更新方法中的使用:
image[r + rres*i] = grd[ratio];
//With image being a vector<unsigned int>, which is then used as data source for a `SDL_Texture` using `SDL_UpdateTexture`
不过,它只能部分起作用。当我只使用黑色/白色渐变时,生成的图像符合预期:
渐变文件:
2
0 000000ff
1 ffffffff
但是,当我使用更彩色的渐变(Ultra Fractal gradient 的线性版本,下面的输入文件)时,图像与预期结果相差甚远图像仍然没有显示想要的颜色:
渐变文件:
5
0 000764ff
.16 206bcbff
.42 edffffff
.6425 ffaa00ff
0.8575 000200ff
我做错了什么?我已经多次重写operator[] 方法,没有任何改变。
欢迎对我的代码提出澄清或一般评论的问题。
【问题讨论】:
-
你真的应该把很多代码从
operator[]移到读取约束的方法中。使用已排序的vector而不是map来保存约束,并尽早将它们解析为单独的 RGBA 组件。 -
哦,如果您将 RGBA 组件存储在它自己的类中,您可能应该将对这些颜色进行基本数学运算的方法放在该类中。
-
为什么地图会有问题?我之前实际上使用了一个向量,但后来切换到了一个映射,因为映射中的值按键升序排序,这在初始化时给出了对数访问时间。
-
RGBA 只是一个无符号整数,
operator[]实际上是读取约束的方法。 -
糟糕,您对正在排序的地图是正确的。我的观点仍然是该函数中的代码过多。