c++ - Linear color gradient not working -
i'm attempting create color gradient class mandelbrot set explorer.
it reads color constraints (rgba8888 color , position between 0 , 1) text file , adds them vector, lateron used determine colors @ position.
to compute color, algorithm searches next constraint either side given position, splits color 4 single channels, , then, each one, searches lower of both , adds portion of difference equal ratio (x-lpos)/(upos-lpos) lower color. afterwards, channels shifted , ored together, , returned rgba8888 unsigned integer. (see code below.)
edit: rewrote gradient class, fixing issues , making more readable sake of debugging (it gets slow hell, though, -os more or less takes care of that). however, it's still not it's supposed be.
class gradient { //remade, irrelevant methods , 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 , 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 , return return (red << 24) | (green << 16) | (blue << 8 ) | alpha; } void addconstraint(unsigned int color, double position) { constraints[position] = color; } }; usage in update method:
image[r + rres*i] = grd[ratio]; //with image being vector<unsigned int>, used data source `sdl_texture` using `sdl_updatetexture` it works partially, though. when use black/white gradient, resulting image intended:
gradient file:
2 0 000000ff 1 ffffffff however, when use more colorful gradient (a linear version of ultra fractal gradient, input file below), the image far intended result image still doesn't show desired coloring:
gradient file:
5 0 000764ff .16 206bcbff .42 edffffff .6425 ffaa00ff 0.8575 000200ff what doing wrong? i've rewritten operator[] method multiple times, without changing.
questions clarification or general remarks on code welcome.
your problem due over-complicated interpolation function.
when linearly interpolating in range a .. b using factor r (with range 0 .. 1) indicate position in range it's unnecessary determine whether a or b greater. either way around can use:
result = + r * (b - a) if r == 0 trivially shown a, , if r == 1 a - a cancels out leaving b. if r == 0.5 result (a + b) / 2. doesn't matter if a > b or vice-versa.
the preferred formulation in case, since avoids b - a subtraction possibly hits range clamping limits is:
result = (1 - r) * + r * b; which given appropriate * , + operators on new rgba class gives trivial implementation of mid function (with no need per-component operations since they're handled in operators):
static rgba mid(const rgba& a, const rgba& b, double r) { return (1.0 - r) * + r * b; } see https://gist.github.com/raybellis/4f69345d8e0c4e83411b, i've refactored rgba class put clamping operations in constructor rather within individual operators.
Comments
Post a Comment