How to do single color linear interpolation? - c++

I need to do color interpolation of single color(not interpolation from one color to another color).
For an example, if the color is yellow (dark yellow) should be interpolated to light yellow within certain duration, which means for each time step color interpolation should happen within the color and after that duration/time step reverse interpolation (light yellow to dark yellow) should start for certain time step, so this cycle continues until the user stops it through request command.
Basically I need to change brightness.
using color_t = std::array<float,3>;
// we can consider the value from 0-255
color_t yellow{1,1,0}; //as we increase yellow[2], it move towards light yellow
color_t green{0,1,0}; //dark green
// as we increase green[2],it move towards light green
color_t red{1,0,0};
// as we increase red[1],it move towards light red
color_t blue{0,0,1};
// as we increase blue[1],it move towards light blue
timeStepCount = 0;
time_step = 100;
void Linear(std::array<float,3>&color){
}
In the above function, RGB value (let's say for yellow) for color will be passed by reference, so for each time step, I need to get the different RGB values of the same color(as I mentioned above, from dark to light and light to dark).
I need to have the generic linear function, which should work for any color.
I know that I need to find a mathematical equation in order to solve it.
But also okay if I get any solution to above mentioned colors.

Related

Generating a proper alpha (transparency) value out of a PBR material

I'm writing a PBR shader and I'm trying to determine the correct way to generate the alpha value that is output for the image. The goal is to have a final image that is 'premultiplied alpha', so it can be used with another Over composite operation later on (say, compositing it over another background image). This all works great, except for the case of specular highlights on transparent surfaces.
Reading this article:
https://google.github.io/filament/Filament.md.html#lighting/transparencyandtranslucencylighting
In particular:
Observe a window and you will see that the diffuse reflectance is
transparent. On the other hand, the brighter the specular reflectance,
the less opaque the window appears. This effect can be seen in figure
63: the scene is properly reflected onto the glass surfaces but the
specular highlight of the sun is bright enough to appear opaque.
They also include the code snippet:
// baseColor has already been premultiplied
vec4 shadeSurface(vec4 baseColor) {
float alpha = baseColor.a;
vec3 diffuseColor = evaluateDiffuseLighting();
vec3 specularColor = evaluateSpecularLighting();
return vec4(diffuseColor + specularColor, alpha);
}
When rendering glass the metallic level would be 0, so it's not pulling from the baseColor at all, and just using the specular level. This all makes sense and means specular highlights can still occur even on the transparent glass, as per the above quote. I don't want to just multiply by alpha at the end, since my baseColor texture would already be a premultiplied alpha image, such as something containing a decal. For example let's say I'm drawing a pane of glass with a sticker on it that's the letter 'A'.
My question is: for a pixel that has a specular highlight on a transparent portion of the glass, what should the alpha value be for compositing to work downstream? The alpha would be 0 according to the above code, which would make an Over operation later on behave poorly. I say this since a property of pre-multiplied alpha is that max(R,G,B) <= A, but this specular highlight would have max(R,G,B) > A. This would result in the over operation being additive between the specular highlight and the background it's being composited over, blowing out the final image.
Should I set the alpha to max(specular, alpha), to give a more useful alpha value for these pixels? Is there a more 'correct' way to handle this?
Thanks
The idea behind the pre-multiplied approach is we assume that the alpha/opacity only affects the diffuse (i.e. the light that goes inside the material/surface), whereas the specular is assumed to be unaffected (at least for the case of a dielectric, the light is simply reflected off the surface un-tinted).
In essence, you should have :
return vec4(diffuseColor * alpha + specularColor, alpha);
Where the alpha is 'pre-multiplied' with the diffuse colour, while the specular colour is left at full intensity (as it should).
Your blend mode will also need to follow suit : off the top of my head one/one for the source/destination colours since the colour will need to be rendered in an additive fashion.

Shader that replaces colors

I want to make a shader that replace a color to be applied to a plain color character, but I can't just replace the color because the image contains pixels that are an average of two border colors.
For example the image looks like this:
Assuming that I want to change the color of the shirt, I want to replace the red color for a green one, but at the edges there are pixels that are not red:
Any ideas how to calculate the resultant color of one of those pixels?
Do you know which are the major colours in advance?
If not then a simple solution for finding them is to generate a histogram — scan the entire image and for each pixel that is the same as all four of its neighbours, add one to a count for the colour it contains. At the end, keep only those colours that fill at least a non-negligible portion of the display, e.g. at least 5% of those pixels that are not transparent.
Dealing with black borders is easy: use a luminance/chrominance colour space, and always leave luminance alone, remapping only chrominance. Factoring out brightness has a bonus: it collapses colour substitution from a 3d problem to a 2d problem.
If this weren't GLSL then a solid solution might be for each pixel that is not one of the selected major colours might be (i) find the nearest pixel that is a major colour; (ii) then find the nearest pixel that is a major colour but not the one found in (i). Use normal linear algebra to figure out the distance of that pixel on the 2d line from the one colour to the other. Substitute the colours, reinterpolate and output.
Being that it is GLSL, so "find the nearest" isn't especially realistic, assuming the number of major colours is small then just do it as distance from those lines. E.g. suppose you have five colours. Then that's 10 potential colour transitions in total — from each of the five colours there are four other options, suggesting twenty transitions, but half of them are exactly the same as the other half because they're just e.g. red to blue instead of blue to red. So ten.
Load those up as uniforms and just figure out which transition gradient the colour is closest to. Substitute the basis colours. Output.
So, in net:
transform (R, G, B) to (Y, x, y) — whether YUV or YIQ or Y doesn't matter, just pick one;
perform distance from a line for (x, y) and the colour transition gradients identified for this image;
having found the transition this pixel is closest to and its distance along that transition, substitute the end points, remap;
recombine with the original Y, convert back to RGB and output.
That's two dot products per colour transition gradient to establish closest, then a single mix to generate the output (x, y)/
Let Rx, Gx, Bx = Pixel values of color X (Red in your case) to be removed/replaced.
Let Ry, Gy, By = Pixel values of color Y (Green in your case) to be used as new color.
Then you will iterate over all pixels and using clever condition (below), identify the pixel that needs to be processed.
If Rc is current value of the selected pixel color (does not matter what combination of red and yellow is), then final values of the pixel are:
Rf = Rc - Rx + Ry
Gf = Gc - Gx + Gy
Bf = Bc - Bx + By
Of course, this processing should NOT happy for all pixels. Clever condition to identify only relevant pixels could be : If pixel color is Red or least one adjacent pixel is Red/Yellow.
UPDATE: Another clever condition using current pixel only:
This involves removing border colors YELLOW or BLACK color from the current color and checking if it is RED.
Rc - R(yellow) == R(RED) AND
Gc - G(yellow) == G(RED) AND
Bc - B(yellow) == B(RED)
OR
Rc - R(black) == R(RED) AND
Gc - G(black) == G(RED) AND
Bc - B(black) == B(RED)

Are Red and Green somehow more dominant than Blue (RGB)?

In OpenGL, I made a sphere and gave every Fragment the Color of its normalized position. The sphere is right at the origin so the sphere should be covered with smooth color gradients between red, green, and blue, while on every axis, the color is pure(x - red, y - green, z - blue).
but not like I expected i see this shape when i look down the Z/Blue Axis
I played around a little and compared the gradients between the different colors
(looking down the x axis with zero red color)
In this image, it looks like the Green color is somehow more dominant than the blue, as if it was sprayed on top of it. Also the Blue seems to be deminished by the black.
(looking down the y axis with zero green color)
In this image there seems to be a smoother gradient but i´d still say there is more red than blue in the image but this might be my individual perception and the picture is not perfectly symmetrical aswell.
(looking down the z axis with zero blue color)
To me it looks like Green and Red are more dominant than blue for some reason.
But what originally brought up this question is the weird hard gradient i got (first image). I dont think it is a bug in my shaders, because i never treat any color individually.
What could cause this behaviour?
PS: I have not implemented alpha yet and i am not using alpha anywhere in my shader (where i use a vec4 for color, the 4th component is always 1.0)

SDL blending causing incorrect frame interpolation

While working on a particle engine in SDL, I stumbled over the following problem:
After implementing a frame interpolation technique as described here (Step 6: Optimization, I'm basically drawing the last frame with an alpha of 254 to the current frame) so that it fades out), I noticed that some pixels which were supposed to gradually fade from white to black, ended up staying gray, with rgba values of 112 to be precise. After doing some math I've found what's causing this: every frame I multiply the rgba values of the last frame by 254/255, which works fine up to and excluding 112.
Then something funny happens. When you do the following: round(112/255*254)=112, the values will stay the same (I'm rounding the number because the end value is to be stored as an 8bit color value of a pixel), meaning that my fading technique using alpha doesn't work anymore. The problem is that I would like these gray pixels which stay at 112 to fade out further. The question is, how would I achieve such a thing within SDL?
I know I could just make the value of 254 lower so that this sort of minimum decreases but I would like my particles to fade out really gently (I'm making a 60fps game). I've also considered creating an OpenGL graphics engine myself (so that I could use floating point textures, which do have to precision I need in this case), but I'm simply not good enough at OpenGL and lack the time to do such a thing.
The reason I need to use a texture for storage is that I would like to have particles which emit trails (as if you stopped clearing your frame buffers and you moved an object, but instead of the screen becoming a mess the older pixels would fade out)
currentFrame->renderTo();//Draw to the current frame rendertarget
graphics.clear(Color(0,0,0,0)); //Clear the screen using the given color
graphics.scale=1.0f; //Manipulate pixel size (for visible pixel art)
SDL_SetTextureBlendMode(lastFrame->texture, SDL_BLENDMODE_NONE);
//Set blendmode to opaque
graphics.drawTexture(lastFrame,graphics.camera.position,Color(255,255,255,254));
//Draw the last frame
SDL_SetTextureBlendMode(lastFrame->texture, SDL_BLENDMODE_BLEND);
//Revert blendmode to alpha blending
I would use a global float variable called 'decay' to store the non-rounded alpha value.
float decay = 255.0;
[...]
decay = decay / 255.0 * 254.0;
Uint8 alpha = round(decay);
If you need one 'decay' value per pixel then you could declare a struct for a particle:
typedef struct {
int active;
float x,y;
float dx,dy; // directions for x and y
float decay;
Uint8 r,g,b,a; // colour
} s_dots;
s_dots dots[MAX_NUMBER_OF_DOTS];

Raphael getPixelColour

I have a colour with rgb values 17, 30, 62.
I did linear gradient fill of a rect with this colour.
On mouse over of rect i want to change the colour value in a text box.
Is there any function or ratio to increase and decrease RGB values programatically
Then i can get the colour back with Raphael.rgb
Raphael cannot help you get the color at a specified pixel, as it only deals with vector graphics (SVG/VML). The rendering is done by the browser.
In the color picker example, the color is obtained from the coordinates in the circle -- the picker knows beforehand, which color it would find in a specified point. It does not check the color of the pixel under the cursor.
If you have a linear gradient with known edge colors it is a matter of linear interpolation to figure out the color of the gradient in any point (unless there is some transparency involved). Find the distance from the two anchor points of the gradient, estimate the relative distance to each and combine the colors using these coefficients.