c++ Fade between colors? (Arduino) - c++

I currently have this thats fading between 2 set colours:
for(int i=0;i<nLEDs;i++){
a = (255 / 100) * (incomingByte * sensitivity);
r = (r * 7 + a + 7) / 8;
g = (g * 7 + (255 - a) + 7) / 8;
b = 0;
FTLEDColour col = { r , g , b };
led.setLED(i, col);
}
But now im trying to allow users to enter their own colours:
// > Colour fade, Start colour
int colFade1Red = 0;
int colFade1Green = 255;
int colFade1Blue = 0;
// > Colour fade, End colour
int colFade2Red = 255;
int colFade2Green = 0;
int colFade2Blue = 0;
int fadeAm = 7; // Fade speed
with the fading code:
void ColourFade(){
for(int i=0;i<nLEDs;i++){
r = ctest(colFade1Red, colFade2Red, r);
g = ctest(colFade1Green, colFade2Green, g);
b = ctest(colFade1Blue, colFade2Blue, b);
FTLEDColour col = { r , g , b };
led.setLED(i, col);
}
}
int ctest(int col1, int col2, int cur){
int temp = col1 - col2;
if(temp < 0) { temp = -temp; }
int alp = (temp / 100) * (incomingByte * sensitivity);
if(col1 < col2){
return (cur * fadeAm + (col2 - alp) + fadeAm) / (fadeAm +1 );
} else {
return (cur * fadeAm + alp + fadeAm) / (fadeAm +1 );
}
}
But this starts with the Second user colour and fades into pink. How would I fade colours properly?
Also "incomingByte" is a value between 0 and 100, and the code is in a update loop.

Smooth transitions between colours is best done in a different colour space (IMHO).
As an example, to transition from bright red to bright green, do you want to go via bright yellow (around the edge of the colour wheel) or via #808000 (murky yellow) - which is what a straight line interpolation would give you in the RGB domain.
Having done this for my Moodlamp app, I used the HSL colour space. I specified a start colour and end colour, along with a number of steps for the transition to take. That enabled me to calculate how much to adjust H, S and L by at each point in the transition.
Only at the point of using the colour did I convert back to RGB.
You can see the javascript code here (please bear in mind it's the first Javascript I ever wrote, so if it seems non-idiomatic, that's probably why!):
https://github.com/martinjthompson/MoodLamp/blob/master/app/assistants/lamp-assistant.js

It's impossible to fade to pink beacuse you are starting from red and ending with green.
To avoid this kind of mistake I suggest you to write an object oriented code.
If you don't want to write the classes to handle a 3D vectonr you can use the Arduino Tinker Library
I wrote this example for you:
#include <Vect3d.h>
#include <SerialLog.h>
Tinker::Vect3d<float> red(255,0,0);
Tinker::Vect3d<float> green(0,255,0);
Tinker::SerialLog serialLog;
void setup(){
Serial.begin(9600);
serialLog.display("Fade color example");
serialLog.endline();
}
void loop(){
//fade factor computation
const uint32_t t = millis()%10000;
const float cosArg = t/10000.*3.1415*2;
const float fade = abs(cos(cosArg));
//Here's the color computation... as you can see is very easy to do!! :)
Tinker::Vect3d<uint8_t> finalColor(red*fade + green*(1-fade));
//We print the vect3d on the arduino serial port
Tinker::LOG::displayVect3d(finalColor,&serialLog);
serialLog.endline();
delay(500);
}
Which prints the following output on the serial port
Fade color example
V[255;0;0]
V[242;12;0]
V[206;48;0]
V[149;105;0]
V[78;176;0]
V[0;254;0]
V[79;175;0]
V[150;104;0]
V[206;48;0]
V[242;12;0]
V[254;0;0]
V[242;12;0]
V[205;49;0]
V[148;106;0]
V[77;177;0]
V[1;253;0]
V[80;174;0]
V[151;103;0]
hope that this helps :)

uint8_t clrR = abs(255 * cos(<some var that changes in time>));
same for clrB & clrG

Related

Pixels Overlay With transparency

I have 2 pixels in B8G8R8A8 (32) format.
Both pixels (top and bottom) has transparency (Alpha channel < 255 )
What is the way (formula) to overlay top pixel on the bottom one ?
(without using 3rd parties).
I tried to do something like this
struct FColor
{
public:
// Variables.
#if PLATFORM_LITTLE_ENDIAN
#ifdef _MSC_VER
// Win32 x86
union { struct{ uint8 B,G,R,A; }; uint32 AlignmentDummy; };
#else
// Linux x86, etc
uint8 B GCC_ALIGN(4);
uint8 G,R,A;
#endif
#else // PLATFORM_LITTLE_ENDIAN
union { struct{ uint8 A,R,G,B; }; uint32 AlignmentDummy; };
#endif
//...
};
FORCEINLINE FColor AlphaBlendColors(FColor pixel1, FColor pixel2)
{
FColor blendedColor;
//Calculate new Alpha:
uint8 newAlpha = 0;
newAlpha = pixel1.A + pixel2.A * (255 - pixel1.A);
//get FColor as uint32
uint32 colora = pixel1.DWColor();
uint32 colorb = pixel2.DWColor();
uint32 rb1 = ((0x100 - newAlpha) * (colora & 0xFF00FF)) >> 8;
uint32 rb2 = (newAlpha * (colorb & 0xFF00FF)) >> 8;
uint32 g1 = ((0x100 - newAlpha) * (colora & 0x00FF00)) >> 8;
uint32 g2 = (newAlpha * (colorb & 0x00FF00)) >> 8;
blendedColor = FColor(((rb1 | rb2) & 0xFF00FF) + ((g1 | g2) & 0x00FF00));
blendedColor.A = newAlpha;
return blendedColor;
}
But the result is far not what I want :-)
I looked for some Alpha blending formulas (I did never understand how would I calculate a new alpha of the overlay) -> perhaps I was going in a wrong direction ?
Edit:
Changing the newAlpha to newAlpha = FMath::Min(pixel1.A + pixel2.A, 255);
Actually gives a much better result, but is it right to calculate it like this ? Am I missing something here?
Working Example Based On Accepted Answer)
FORCEINLINE FColor AlphaBlendColors(FColor BottomPixel, FColor TopPixel)
{
FColor blendedColor;
//Calculate new Alpha:
float normA1 = 0.003921568627451f * (TopPixel.A);
float normA2 = 0.003921568627451f * (BottomPixel.A);
uint8 newAlpha = (uint8)((normA1 + normA2 * (1.0f - normA1)) * 255.0f);
if (newAlpha == 0)
{
return FColor(0,0,0,0);
}
//Going By Straight Alpha formula
float dstCoef = normA2 * (1.0f - normA1);
float multiplier = 255.0f / float(newAlpha);
blendedColor.R = (uint8)((TopPixel.R * normA1 + BottomPixel.R * dstCoef) * multiplier);
blendedColor.G = (uint8)((TopPixel.G * normA1 + BottomPixel.G * dstCoef) * multiplier);
blendedColor.B = (uint8)((TopPixel.B * normA1 + BottomPixel.B * dstCoef) * multiplier);
blendedColor.A = newAlpha;
return blendedColor;
}
Start by assuming that there is a third pixel below that happens to be opaque.
For the further notations, I will assume that alpha values are in [0,1].
Given: three pixels with the first one being on top, colors c_1, c_2, c_3, alpha values a_1, a_2, a_3 = 1
Then the resulting alpha value is obviously 1 and the color is
(a_1)*c_1 + (1-a_1)(*a_2)*c_2 + (1-a_1)*(1-a_2)*c_3
Now, we want to find some values c_k, a_k so that the formula above equates
(a_k)*c_k + (1-a_k)*c_3
We can solve this in two steps:
(1-a_k) = (1-a_1)*(1-a_2)
->
a_k = 1-(1-a_1)*(1-a_2)
and
(a_k)*c_k = (a_1)*c_1 + (1-a_1)(*a_2)*c_2
->
c_k = [(a_1)*c_1 + (1-a_1)(*a_2)*c_2] / a_k
Use those formulas (with a different range for your alpha values) and you get your desired color.
(Don't forget to catch a_k = 0)
edit: Explanation of the third pixel:
When you use your two pixels in any way, that is doing something that results it in being used to display something, they will be put over some other existing color that is opaque. For example, this might be the background color, but it could also be some color that is the result of applying many more transparent pixels on some background color.
What I now do to combine your two colors is to find a color that behaves just like those two colors. That is, putting it on top of some opaque color should result in the same as putting the original two colors on top of it. This is what I demand of the new color, resulting in the formula I use.
The formula is nothing than the result of applying two colors in succession on the third one.

How to realize Digital fill light in Opencv

I want to realize the function of fill-light by use OpenCV, but There have some problem. Black part of pics is too dark, Photos become blurred, i don't know how to Optimization code。that my code:
V, value, 0~100, increase the amplitude of the brightness.
S,Scope, 0~255, dark is all less than S.
increase exposure to light dark photos increment, unchanged, so to see more details of the dark.
m_imgOriginal: original image ,type:Mat
m_imgNew: new image , clone from m_imgOriginal ,type:Mat
int OpenCVClass::AddExposure(int v, int s)
{
int new_r = v*m_mean_val.val[0] / 150;
int new_g = v*m_mean_val.val[1] / 150;
int new_b = v*m_mean_val.val[2] / 150;
for (int y = 0; y < m_imgOriginal.rows; y++)
{
auto ptr = m_imgOriginal.ptr<uchar>(y);
auto qtr = m_imgNew.ptr<uchar>(y);
for (int x = 0; x < m_imgOriginal.cols; x++)
{
int mean = (ptr[0] + ptr[1] + ptr[2]) / 3;
if (mean <= s)
{
int r = ptr[0] + new_r;
qtr[0] = r>255 ? 255 : r;
int g = ptr[1] + new_g;
qtr[1] = g>255 ? 255 : g;
int b = ptr[2] + new_b;
qtr[2] = b>255 ? 255 : b;
int newMean = (qtr[0] + qtr[1] + qtr[2]) / 3;
if (newMean > s)
{
int nr = ptr[0] + (s - mean) ;
int ng = ptr[1] + (s - mean) ;
int nb = ptr[2] + (s - mean) ;
qtr[0] = nr>255 ? 255 : nr;
qtr[1] = ng>255 ? 255 : ng;
qtr[2] = nb>255 ? 255 : nb;
}
}
else
{
qtr[0] = ptr[0];
qtr[1] = ptr[1];
qtr[2] = ptr[2];
}
ptr += 3;
qtr += 3;
}
RenderBuffer(m_imgNew, m_displayBuffer);
}
return 0;
}
Optimization before
Optimization after
First, I would suggest to calculate a luminance value for each pixel, when testing agains 's'. I mean calculate 'mean' a different way (see this link on how to calculate luminance):
http://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
Second, you are dealing with an 8 bit per channel image, don't expect near-or-perfect dark pixels to have any extra detail when you make them "brighter", they will just become grey or whiter.
Third, when "adding" brightness, I suggest using the HSL representation of pixel color values and increasing the luminance. In pseudocode:
1) Convert pixel color from RGB to HSL.
2) Increase luminance (or 'lightness').
3) Convert back pixel color to RGB.

Resizing a picture vc++

Is there any function that quickly resizing a picture in Visual C++? I want to made a copy of original picture that would be x times smaller. Then I would like to placed it at the center of black bitmap. The black bitmap would be in the size of first picture.
Here is original picture: https://www.dropbox.com/s/6she1kvcby53qgz/term.bmp
and this is effect that i want to receive: https://www.dropbox.com/s/8ah59z0ip6tq4wd/term2.bmp
In my program I use Pylon's libraries. The images are in CPylonImage type.
Some simple code to handle resizes portably:
For all cases the following legend applies:
w1 - the width of the original image
h1 - the height of the original image
pixels - an array of int with the pixel data
w2 - desired width
h2 - desired height
retval - this is the returned value, it is a new pixel array which contains the manipulated image.
For Linear Interpolation:
I cannot find this on my drive at present (issues with a new hdd) so have included Bilinear:
For Bilinear Interpolation:
Bilinear Interpolation function
int* resizeBilinear(int* pixels, int w1, int h1, int w2, int h2)
{
int* retval = new int[w2*h2] ;
int a, b, c, d, x, y, index ;
float x_ratio = ((float)(w1-1))/w2 ;
float y_ratio = ((float)(h1-1))/h2 ;
float x_diff, y_diff, blue, red, green ;
int offset = 0 ;
for (int i=0;i<h2;i++) {
for (int j=0;j<w2;j++) {
x = (int)(x_ratio * j) ;
y = (int)(y_ratio * i) ;
x_diff = (x_ratio * j) - x ;
y_diff = (y_ratio * i) - y ;
index = (y*w1+x) ;
a = pixels[index] ;
b = pixels[index+1] ;
c = pixels[index+w1] ;
d = pixels[index+w1+1] ;
// blue element
// Yb = Ab(1-w1)(1-h1) + Bb(w1)(1-h1) + Cb(h1)(1-w1) + Db(wh)
blue = (a&0xff)*(1-x_diff)*(1-y_diff) + (b&0xff)*(x_diff)*(1-y_diff) +
(c&0xff)*(y_diff)*(1-x_diff) + (d&0xff)*(x_diff*y_diff);
// green element
// Yg = Ag(1-w1)(1-h1) + Bg(w1)(1-h1) + Cg(h1)(1-w1) + Dg(wh)
green = ((a>>8)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>8)&0xff)*(x_diff)*(1-y_diff) +
((c>>8)&0xff)*(y_diff)*(1-x_diff) + ((d>>8)&0xff)*(x_diff*y_diff);
// red element
// Yr = Ar(1-w1)(1-h1) + Br(w1)(1-h1) + Cr(h1)(1-w1) + Dr(wh)
red = ((a>>16)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>16)&0xff)*(x_diff)*(1-y_diff) +
((c>>16)&0xff)*(y_diff)*(1-x_diff) + ((d>>16)&0xff)*(x_diff*y_diff);
retval[offset++] =
0xff000000 | // hardcoded alpha
((((int)red)<<16)&0xff0000) |
((((int)green)<<8)&0xff00) |
((int)blue) ;
}
}
return retval;
}
For Nearest Neighbour:
int* resizePixels(int* pixels,int w1,int h1,int w2,int h2)
{
int* retval = new int[w2*h2] ;
// EDIT: added +1 to remedy an early rounding problem
int x_ratio = (int)((w1<<16)/w2) +1;
int y_ratio = (int)((h1<<16)/h2) +1;
//int x_ratio = (int)((w1<<16)/w2) ;
//int y_ratio = (int)((h1<<16)/h2) ;
int x2, y2 ;
for (int i=0;i<h2;i++) {
for (int j=0;j<w2;j++) {
x2 = ((j*x_ratio)>>16) ;
y2 = ((i*y_ratio)>>16) ;
retval[(i*w2)+j] = pixels[(y2*w1)+x2] ;
}
}
return retval;
}
Now, the code above is designed to be portable and should work with very little modification in C++, C, C# and Java (I have used the code above for all 4 when needed), which eliminates the need for an external library and allows you to process any array of pixels, so long as you can represent them in the format for the code above.
To place the manipulated image in the middle of a black background, all you would need to do is copy the data into an array of the original at the right locations and populate all the other locations with the values for black:)
Hope this helps, as I have not time to comment it all at present, however I can if needs be at a later point today or tomorrow:)

Fading Arduino RGB LED from one color to the other?

I've currently managed to get my LED to cycle through eight colors that I've selected. Everything is working correctly, except that I want to go for a more natural feel, and would like to fade / transition from one color to the next, instead of having them just replace one another.
Here's my code so far:
int redPin = 11;
int greenPin = 10;
int bluePin = 9;
void setup()
{
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
}
void loop()
{
setColor(250, 105, 0); // Yellow
delay(1000);
setColor(250, 40, 0); // Orange
delay(1000);
setColor(255, 0, 0); // Red
delay(1000);
setColor(10, 10, 255); // Blue
delay(1000);
setColor(255, 0, 100); // Pink
delay(1000);
setColor(200, 0, 255); // Purple
delay(1000);
setColor(0, 255, 0); // Green
delay(1000);
setColor(255, 255, 255); // White
delay(1000);
}
void setColor(int red, int green, int blue)
{
analogWrite(redPin, 255-red);
analogWrite(greenPin, 255-green);
analogWrite(bluePin, 255-blue);
}
What the other answers omit about this topic is the fact that that human perception of light intensity is logarithmic, not linear. The analogWrite() routines are setting the output pin's PWM duty cycle, and are linear. So by taking the minimum duty cycle (say 0) and maximum duty cycle (say, for the sake of easy math this is 10) and dividing it into equal chunks, you will be controlling the intensitiy linearly which will not give satisfying results.
What you need to do instead is set your intensity exponentially. Let's say your maximum intensity is 255. You can generate this result by treating your intensity as a power to raise some number to. In our case, given that we are dealing with computers that like binary, powers of two are convenient. So,
2^0 =1
2^8=256
so we can have 8 intensity levels. Actually, note that out minimum is now not fully off (it is 1 not 0) and our maximum is out of range (256 not 255). So we modify the formula to be
output = 2 ^ intensity - 1
Or in code
int output = 1<<intensity - 1;
This yields values from 0 to 255 for intensity levels from 0 to 8 (inclusive), so we actually get nine levels of intensity. If you wanted smoother transitions (i.e. more levels of intensity), and still use logarithmic intensity you'll need floating-point math.
If you apply this method of calculating intensity to each channel (R, G, B) then your perception will be in accord with what your code says it should be.
As fars as how to smoothly transition between various colors, the answer depends on how you want to navigate the color space. The simplest thing to do is to think about your color space as a triangle, with R, G, and B, as the verteces:
The question then is how to navigate this triangle: you could go along the sides, from R, to G, to B. This way you will never see white (all channels fully on) or "black" (all fully off). You could think of your color space as a hexagon, with additional purple (R+B), yellow (G+B), and brown (R+G) colors, and also navigate the perimeter (again, no white or black). There are as many fading possibilities as there are ways of navigating insides these, and other figures we might think of.
When I built fading programs like this the color space and the traversal I liked was as follows: think of each channel as a binary bit, so now you have three (R, G, and B). If you think of each color as having some combination of these channels being fully on, you get 7 total colors (excluding black, but including white). Take the first of these colors, fade to it from black and back to black, and then go to the next color. Here's some code that does something like that:
int targetColor = 1;
int nIntensity = 0;
int nDirection = 1; // When direction is 1 we fade towards the color (fade IN)
// when 0 we fade towards black (fade OUT)
#define MAX_INTENSITY 8
#define MIN_INTENSITY 0
#define MAX_TARGETCOLOR 7
void loop() {
for (;;) {
// Update the intensity value
if (nDirection) {
// Direction is positive, fading towards the color
if (++nIntensity >= MAX_INTENSITY) {
// Maximum intensity reached
nIntensity = MAX_INTENSITY; // Just in case
nDirection = 0; // Now going to fade OUT
} // else : nothing to do
} else {
if (--nIntensity <= MIN_INTENSITY) {
nIntensity = MIN_INTENSITY; // Just in case
// When we get back to black, find the next target color
if (++targetColor>MAX_TARGETCOLOR)
targetColor=1; // We'll skip fading in and out of black
nDirection = 1; // Now going to fade IN
} // else: nothing to do
}
// Compute the colors
int colors[3];
for (int i=0;i<3;i++) {
// If the corresponding bit in targetColor is set, it's part of the target color
colors[i] = (targetColor & (1<<i)) ? (1<<nIntensity) -1 : 0;
}
// Set the color
setColor(colors[0], colors[1], colors[2]);
// Wait
delay(100);
}
}
It is indeed possible to fade between different colors. What I'm also usually missing in Arduino books and code on the web is, that it is possible to write C++ classes in Arduino IDE. Therefore, I'm going to show an example that fades between colors using C++ classes.
An issue that should be addressed is on which pins the analogWrite should be done to, because not all pins are capable of Pulse Width Modulation (PWM). On a Arduino device the pins that support PWM are denoted with a tilde '~'. The Arduino UNO has digital pins ~3, ~5, ~6, ~9, ~10 and ~11. And most Arduino use those pins for PWM, but check your device to be sure. You can create PWM on regular digital pins by switching your led on for 1ms and of for 1 ms this mimics 50% power on the LED. Or turn it on 3 ms and of 1 ms this mimics 75% power.
In order to fade a LED you would have to reduce/increase the PWM value and wait a bit. Youl'll have to wait a little while, because otherwise the arduino tries to fade/dim leds thousands of times per second and you won't see a fade effect, although it probably there. So you are looking for a method to gradually reduce/increase the second parameter to analogWrite( ) for three LEDs; For a more thorough explanation see for example chapter 7 of Arduino Cookbook. That book is a good read for Arduino fans anyway!
So I adapted the code from the OP to contain a 'rgb_color' class that is more or less just a container for red, green and blue values. But more importantly is the fader class. When an instance of fader is constructed the proper pins should be in the constructor red, green and blue respectively. Than the fader contains a member function void fade( const rgb_color& const rgb_color&) which will do the fading between the in and out color. By default the function will take 256 steps of 10ms from the input color to the output color. (note here due to integer divisions this doesn't really mean that each step 1/256 th, but perceputally you won't notice it).
/*
* LedBrightness sketch
* controls the brightness of LEDs on "analog" (PWM) output ports.
*/
class rgb_color {
private:
int my_r;
int my_g;
int my_b;
public:
rgb_color (int red, int green, int blue)
:
my_r(red),
my_g(green),
my_b(blue)
{
}
int r() const {return my_r;}
int b() const {return my_b;}
int g() const {return my_g;}
};
/*instances of fader can fade between two colors*/
class fader {
private:
int r_pin;
int g_pin;
int b_pin;
public:
/* construct the fader for the pins to manipulate.
* make sure these are pins that support Pulse
* width modulation (PWM), these are the digital pins
* denoted with a tilde(~) common are ~3, ~5, ~6, ~9, ~10
* and ~11 but check this on your type of arduino.
*/
fader( int red_pin, int green_pin, int blue_pin)
:
r_pin(red_pin),
g_pin(green_pin),
b_pin(blue_pin)
{
}
/*fade from rgb_in to rgb_out*/
void fade( const rgb_color& in,
const rgb_color& out,
unsigned n_steps = 256, //default take 256 steps
unsigned time = 10) //wait 10 ms per step
{
int red_diff = out.r() - in.r();
int green_diff = out.g() - in.g();
int blue_diff = out.b() - in.b();
for ( unsigned i = 0; i < n_steps; ++i){
/* output is the color that is actually written to the pins
* and output nicely fades from in to out.
*/
rgb_color output ( in.r() + i * red_diff / n_steps,
in.g() + i * green_diff / n_steps,
in.b() + i * blue_diff/ n_steps);
/*put the analog pins to the proper output.*/
analogWrite( r_pin, output.r() );
analogWrite( g_pin, output.g() );
analogWrite( b_pin, output.b() );
delay(time);
}
}
};
void setup()
{
//pins driven by analogWrite do not need to be declared as outputs
}
void loop()
{
fader f (3, 5, 6); //note OP uses 9 10 and 11
/*colors*/
rgb_color yellow( 250, 105, 0 );
rgb_color orange( 250, 40, 0 );
rgb_color red ( 255, 0, 0 );
rgb_color blue ( 10, 10, 255 );
rgb_color pink ( 255, 0, 100 );
rgb_color purple( 200, 0, 255 );
rgb_color green ( 0, 255, 0 );
rgb_color white ( 255, 255, 255 );
/*fade colors*/
f.fade( white, yellow);
f.fade( yellow, orange);
f.fade( orange, red);
f.fade( red, blue);
f.fade( blue, pink);
f.fade( pink, purple);
f.fade( purple, green);
f.fade( green, white);
}
This is probably what you are looking for. Whenever we want to shift color over the spectrum and trasition the colors in a circular and smooth motion, what we are really doing is shifting light using HUE in the HSI/HSV (Hue, Saturation, Intensity/Value) color space.
Take if you will this figure:
We will attach a value from 0-360 for hue because hue has 360 degrees of color.
A value of 0.00 - 1.00 for saturation, and a value of 0.00 -1.00 for intensity/value
Here is my circuit on the MEGA 2560:
Here is video of this code running:
<iframe width="560" height="315" src="https://www.youtube.com/embed/gGG-GndSKi0" frameborder="0" allowfullscreen></iframe>
So lets build a function that we can pass the hue value and a for loop inside our loop function to call that value 360 times to shift over the full rainbow of color.
//Define the pins we will use with our rgb led
int redPin = 9;
int greenPin = 10;
int bluePin = 11;
//define that we are using common anode leds
#define COMMON_ANODE
void setup()
{
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
}
int rgb[3];
//Arduino has no prebuilt function for hsi to rgb so we make one:
void hsi_to_rgb(float H, float S, float I) {
int r, g, b;
if (H > 360) {
H = H - 360;
}
// Serial.println("H: "+String(H));
H = fmod(H, 360); // cycle H around to 0-360 degrees
H = 3.14159 * H / (float)180; // Convert to radians.
S = S > 0 ? (S < 1 ? S : 1) : 0; // clamp S and I to interval [0,1]
I = I > 0 ? (I < 1 ? I : 1) : 0;
if (H < 2.09439) {
r = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
g = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
b = 255 * I / 3 * (1 - S);
} else if (H < 4.188787) {
H = H - 2.09439;
g = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
b = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
r = 255 * I / 3 * (1 - S);
} else {
H = H - 4.188787;
b = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
r = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
g = 255 * I / 3 * (1 - S);
}
rgb[0] = r;
rgb[1] = g;
rgb[2] = b;
}
void setColor(int red, int green, int blue)
{
#ifdef COMMON_ANODE
red = 255 - red;
green = 255 - green;
blue = 255 - blue;
#endif
analogWrite(redPin, red);
analogWrite(greenPin, green);
analogWrite(bluePin, blue);
}
///here we have our main loop and the for loop to shift color
void loop()
{
//the for loop counts to 360 and because its in our control loop it will run forever
// We will use int i to increment the actual desired color
for (int i=0; i<=360;i++){
hsi_to_rgb(i,1,1);
setColor(rgb[0],rgb[1],rgb[2]);
//Changing the delay() value in milliseconds will change how fast the
//the light moves over the hue values
delay(5);
}
}
If you want to fade between colours, work in a colourspace which makes it easy and then convert back to RGB at the end.
For example, work in HSL colour space, keep S and L constant (say a fully saturated and bright colour) and then "fade" H around the circle - you'll go from red through green, blue and back to red. Convert back to RGB and then use those values for your LED drives. I used this technique for a "mood lamp" app, and other code for the colour space conversion can be found on SO.
You can simplify your code by using a struct for your color.
struct Color
{
unsigned char r;
unsigned char g;
unsigned char b;
};
Then, it is easy to have a fading function
// the old color will be modified, hence it is not given as reference
void fade(Color old, const Color& newColor)
{
// get the direction of increment first (count up or down)
// each of the inc_x will be either 1 or -1
char inc_r = (newColor.r - old.r)/abs(newColor.r-old.r); // note, that the right hand side will be sign extended to int according to the standard.
char inc_g = (newColor.g - old.g)/abs(newColor.g-old.g);
char inc_b = (newColor.g - old.g)/abs(newColor.g-old.g);
fadeOneColor(old.r, newColor.r, inc_r, old);
fadeOneColor(old.g, newColor.g, inc_g, old);
fadeOneColor(old.b, newColor.b, inc_b, old);
}
void fadeOneColor( unsigned char& col_old,
const unsigned char& col_new,
const char inc,
Color& col)
{
while(col_old != col_new)
{
col_old += inc;
SetColor(col);
delay(20);
}
}
I would like to contribute with a more user friendly answer as aids understanding of how it works.
In my example bellow I'm using common anode RGB LED.
In my project however: To set a Color to RGB LED, I send a String via HW Serial.
Command Example: RGB000255000
This Command as String is divided into 4 parts of 3 chars each.
Using the Command Example Above:
"RGB" : To filter where the Command will be executed.
"000" : The 2nd 3 Chars represent Red Value.
"255" : The 3rd 3 Chars represent Green Value.
"000" : The 4th 3 Chars represent Blue Value.
Result: This will Output Green on your LED.
See Code Bellow:
// Set your LED Pins.
const int rPin = 9;
const int gPin = 10;
const int bPin = 11;
// Set the variables that will assign a value to each Color Pin.
int rVal = 255;
int gVal = 255;
int bVal = 255;
// Fade Red Pin (In / Out).
void FadeRed(int red)
{
// When Red Value on Red Pin is Inferior to the New Value: Fade In.
if (rVal < red)
{
// Fade Out.
for (int r = rVal; r <= red; r++)
{
// Set the Variable and Pin values.
rVal = r;
analogWrite(rPin, rVal);
// Delay Slighlty (Synchronously). For Asynchronous Delay; you may try using "millis".
delay(6);
}
}
// When Red Value on Red Pin is Superior to the New Value: Fade Out.
else
{
for (int r = rVal; r >= red; r--)
{
rVal = r;
analogWrite(rPin, rVal);
delay(6);
}
}
}
// Fade Green Pin (In / Out).
void FadeGreen(int green)
{
if (gVal < green)
{
for (int g = gVal; g <= green; g++)
{
gVal = g;
analogWrite(gPin, gVal);
delay(6);
}
}
else
{
for (int g = gVal; g >= green; g--)
{
gVal = g;
analogWrite(gPin, gVal);
delay(6);
}
}
}
// Fade Blue Pin (In / Out).
void FadeBlue(int blue)
{
if (bVal < blue)
{
for (int b = bVal; b <= blue; b++)
{
bVal = b;
delay(6);
analogWrite(bPin, b);
}
}
else
{
for (int b = bVal; b >= blue; b--)
{
bVal = b;
delay(6);
analogWrite(bPin, b);
}
}
}
void FadeColor(int red, int green, int blue)
{
// Debug Only.
Serial.println("\n[+] Received Values");
Serial.println(red);
Serial.println(green);
Serial.println(blue);
// Code.
FadeRed(red);
FadeGreen(green);
FadeBlue(blue);
// Debug Only.
Serial.println("\n[+] Pin Values \n");
Serial.println(rVal);
Serial.println(gVal);
Serial.println(bVal);
}
/* Set RGB LED Color According to String Value. (i.e: RGB000000000) */
void SetColor(String color)
{
// Retrieve the New Color from String.
/* Split a String : Start Position; End Position */
String red = color.substring(3, 6); /* Get the 1st 3 Characters Corresponding to RED */
String green = color.substring(6, 9); /* Get the 2nd 3 Characters Corresponding to GREEN */
String blue = color.substring(9, 12); /* Get the Last 3 Characters Corresponding to BLUE */
int r = atoi(red.c_str());
int g = atoi(green.c_str());
int b = atoi(blue.c_str());
int redVal = 255 - r;
int grnVal = 255 - g;
int bluVal = 255 - b;
FadeColor(redVal, grnVal, bluVal);
}
void setup()
{
pinMode(rPin, OUTPUT);
pinMode(gPin, OUTPUT);
pinMode(bPin, OUTPUT);
pinMode(rPin, HIGH);
pinMode(gPin, HIGH);
pinMode(bPin, HIGH);
analogWrite(rPin, rVal);
analogWrite(gPin, gVal);
analogWrite(bPin, bVal);
}
Here's a fast linear fade between two RGB values stored in uint32_t as 0x00RRGGBB as is used in many addressable RGB pixel strips such as in NeoPixel (and is inspired by some of the code in the NeoPixel Arduino library).
It doesn't take colour space into consideration but still looks nice and smooth in practice.
uint32_t fadeColor(uint32_t const x, uint32_t const y, uint8_t const fade)
{
// boundary cases don't work with bitwise stuff below
if (fade == 0)
{
return x;
}
else if (fade == 255)
{
return y;
}
uint16_t const invFadeMod = (255 - fade) + 1;
uint16_t const fadeMod = fade + 1;
// overflows below to give right result in significant byte
uint8_t const xx[3] // r g b
{
static_cast<uint8_t>((uint8_t(x >> 16) * invFadeMod) >> 8),
static_cast<uint8_t>((uint8_t(x >> 8) * invFadeMod) >> 8),
static_cast<uint8_t>((uint8_t(x >> 0) * invFadeMod) >> 8),
};
uint8_t const yy[3] // r g b
{
static_cast<uint8_t>((uint8_t(y >> 16) * fadeMod) >> 8),
static_cast<uint8_t>((uint8_t(y >> 8)* fadeMod) >> 8),
static_cast<uint8_t>((uint8_t(y >> 0)* fadeMod) >> 8),
};
return ((uint32_t)(xx[0] + yy[0]) << 16) | ((uint32_t)(xx[1] + yy[1]) << 8) | (xx[2] + yy[2]);
}

How do I use texture-mapping in a simple ray tracer?

I am attempting to add features to a ray tracer in C++. Namely, I am trying to add texture mapping to the spheres. For simplicity, I am using an array to store the texture data. I obtained the texture data by using a hex editor and copying the correct byte values into an array in my code. This was just for my testing purposes. When the values of this array correspond to an image that is simply red, it appears to work close to what is expected except there is no shading.
first image http://dl.dropbox.com/u/367232/Texture.jpg
The bottom right of the image shows what a correct sphere should look like. This sphere's colour using one set colour, not a texture map.
Another problem is that when the texture map is of something other than just one colour pixels, it turns white. My test image is a picture of water, and when it maps, it shows only one ring of bluish pixels surrounding the white colour.
bmp http://dl.dropbox.com/u/367232/vPoolWater.bmp
When this is done, it simply appears as this:
second image http://dl.dropbox.com/u/367232/texture2.jpg
Here are a few code snippets:
Color getColor(const Object *object,const Ray *ray, float *t)
{
if (object->materialType == TEXTDIF || object->materialType == TEXTMATTE) {
float distance = *t;
Point pnt = ray->origin + ray->direction * distance;
Point oc = object->center;
Vector ve = Point(oc.x,oc.y,oc.z+1) - oc;
Normalize(&ve);
Vector vn = Point(oc.x,oc.y+1,oc.z) - oc;
Normalize(&vn);
Vector vp = pnt - oc;
Normalize(&vp);
double phi = acos(-vn.dot(vp));
float v = phi / M_PI;
float u;
float num1 = (float)acos(vp.dot(ve));
float num = (num1 /(float) sin(phi));
float theta = num /(float) (2 * M_PI);
if (theta < 0 || theta == NAN) {theta = 0;}
if (vn.cross(ve).dot(vp) > 0) {
u = theta;
}
else {
u = 1 - theta;
}
int x = (u * IMAGE_WIDTH) -1;
int y = (v * IMAGE_WIDTH) -1;
int p = (y * IMAGE_WIDTH + x)*3;
return Color(TEXT_DATA[p+2],TEXT_DATA[p+1],TEXT_DATA[p]);
}
else {
return object->color;
}
};
I call the colour code here in Trace:
if (object->materialType == MATTE)
return getColor(object, ray, &t);
Ray shadowRay;
int isInShadow = 0;
shadowRay.origin.x = pHit.x + nHit.x * bias;
shadowRay.origin.y = pHit.y + nHit.y * bias;
shadowRay.origin.z = pHit.z + nHit.z * bias;
shadowRay.direction = light->object->center - pHit;
float len = shadowRay.direction.length();
Normalize(&shadowRay.direction);
float LdotN = shadowRay.direction.dot(nHit);
if (LdotN < 0)
return 0;
Color lightColor = light->object->color;
for (int k = 0; k < numObjects; k++) {
if (Intersect(objects[k], &shadowRay, &t) && !objects[k]->isLight) {
if (objects[k]->materialType == GLASS)
lightColor *= getColor(objects[k], &shadowRay, &t); // attenuate light color by glass color
else
isInShadow = 1;
break;
}
}
lightColor *= 1.f/(len*len);
return (isInShadow) ? 0 : getColor(object, &shadowRay, &t) * lightColor * LdotN;
}
I left out the rest of the code as to not bog down the post, but it can be seen here. Any help is greatly appreciated. The only portion not included in the code, is where I define the texture data, which as I said, is simply taken straight from a bitmap file of the above image.
Thanks.
It could be that the texture is just washed out because the light is so bright and so close. Notice how in the solid red case, there doesn't seem to be any gradation around the sphere. The red looks like it's saturated.
Your u,v mapping looks right, but there could be a mistake there. I'd add some assert statements to make sure u and v and really between 0 and 1 and that the p index into your TEXT_DATA array is also within range.
If you're debugging your textures, you should use a constant material whose color is determined only by the texture and not the lights. That way you can make sure you are correctly mapping your texture to your primitive and filtering it properly before doing any lighting on it. Then you know that part isn't the problem.