c++ - 线性颜色渐变不起作用

标签 c++ colors

我目前正在尝试为我的 Mandelbrot 集浏览器创建一个颜色渐变类。

它从文本文件中读取颜色约束(RGBA8888 颜色和 0 到 1 之间的位置)并将它们添加到一个 vector 中,该 vector 稍后用于确定特定位置的颜色。

为了计算颜色,该算法从给定位置搜索下一个约束到任一侧,将颜色分成四个单 channel ,然后,对于每个 channel ,搜索两个 channel 中较低的一个并添加一部分差异等于 (x-lpos)/(upos-lpos) 与较低颜色的比率。之后, channel 被移位并一起进行或运算,然后返回为 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`

不过,它只部分起作用。当我只使用黑/白渐变时,生成的图像符合预期:

black-white works flawlessly

渐变文件:

2
0 000000ff
1 ffffffff

然而,当我使用更丰富多彩的渐变(Ultra Fractal gradient 的线性版本,下面的输入文件)时,图像与预期结果相去甚远图像仍然没有显示所需的颜色:

enter image description here

渐变文件:

5
0       000764ff
.16     206bcbff
.42     edffffff
.6425   ffaa00ff
0.8575  000200ff

我做错了什么?我多次重写了 operator[] 方法,没有任何改变。

欢迎对我的代码提出澄清或一般性评论的问题。

最佳答案

您的问题是由于插值函数过于复杂。

当使用另一个因子 r(范围 0 .. 1)在范围 a .. b 中进行线性插值时,以指示位置在该范围内,完全没有必要确定 ab 哪个更大。无论哪种方式,您都可以使用:

result = a + r * (b - a)

如果 r == 0 这通常显示为 a,如果 r == 1 a - a 取消,只留下 b。同样,如果 r == 0.5,则结果为 (a + b)/2a > b 或反之亦然都没有关系。

您的情况下的首选公式是:

result = (1 - r) * a + r * b;

在您的新 RGBA 类上给定适当的 *+ 运算符可以实现您的 mid函数(不需要每个组件的操作,因为它们是在这些操作符中处理的):

static RGBA mid(const RGBA& a, const RGBA& b, double r) {
    return (1.0 - r)  * a + r * b;
}

参见 https://gist.github.com/raybellis/4f69345d8e0c4e83411b ,其中我还重构了您的 RGBA 类,将钳制操作放在构造函数中,而不是放在各个运算符中。

关于c++ - 线性颜色渐变不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29377491/

相关文章:

c++ - connect() 超时不工作

c++ - 缓存多个 key 哈希

Java 文本字段 2 颜色

linux - 我可以更改 Linux 终端中的默认响应颜色吗?

r - ggplot2:通过设置连续色标处理极值

c++ - 调用未知子类的虚方法

c++ - 寻找类似 fetch_add 的atomic<double>之类的东西

c++ - 对 vector 的 vector 进行排序

python - 如何将 ipython 语法突出显示添加到 pygmentize?

r - 在 R 中设置自定义色标