simplified my goal is to display a transitional Background and some shapes. This shapes are not moving hard rasterized by 1 pixel, more like .1 each cycle. So I need a way to interpolate the movement between the surrounding Neopixels.
Background works fine, so it's not relevant for now.
For the shapes the first try was to show a smooth movement of a square hardcoded. This works suitable, even its not bug free. I put the Code of the first attempt at the very end.
After that I wanted to implement an bitmap mask to show something more complex . That's where I am at currently. First of this attempt is to assume the whole mask is completly filled (again hardcoded).
The LEDs mostly keep completely on or off.
How do I get them fade them in an out at the outer sides?
I use an AI Thinker ESP 32 and 200 WS2812Bs.
Please ask any more infos that are required. Of course if you spot that my approach is unsuitable to begin with, pls tell me.
Infos for the Code: don't get lost on the "circle" variables. At the eary steps I showed a circle and soon realized its easier to step back to a Circle while working at the interpolation.
My Code with the bitmap
#include <Adafruit_NeoPixel.h>
#define PIN_NEO_PIXEL 13
#define NUM_PIXELS 400
#define num_row 20
#define num_col 20
#define circle_size_body 4
#define circle_size_border 5
#define circle_size_corona 7
#define DELAY_INTERVAL 100
float circle_PosX = 10;
float circle_PosY = 10;
int circle_direction = 1;
enum eIntersectingPart { None, Body, Border, Corona };
Adafruit_NeoPixel NeoPixel(NUM_PIXELS, PIN_NEO_PIXEL, NEO_GRB + NEO_KHZ800);
void setup()
{
NeoPixel.setBrightness(100);
NeoPixel.begin();
Serial.begin(115200); // set up Serial library at 9600 bps
}
float backgroundShift = 0;
float worldSpeed = .05;
void loop()
{
if(circle_PosY <= 0 && circle_direction < 0
|| circle_PosY >= 10 && circle_direction > 0)
circle_direction *= -1;
circle_PosY += worldSpeed * circle_direction;
circle_PosX += worldSpeed * circle_direction;
Serial.print("circle_PosX ");
Serial.print(circle_PosX);
Serial.print(", circle_PosY ");
Serial.print(circle_PosY);
NeoPixel.clear();
//Hintergrund setzen
// setBackgroundColor();
//Kreis malen
drawCircle();
// Serial.print("bgShift: ");
// Serial.flush();
NeoPixel.show(); // send the updated pixel colors to the NeoPixel hardware.
// Serial.println(backgroundShift);
backgroundShift += worldSpeed;
delay(100); // off time
}
uint32_t setBackgroundColor() {
for(int led = 0; led < NUM_PIXELS; led++) {
int coordinates[2];
coordinateByLed(coordinates, led);
byte ambientColors[3] = { 0, 0, 255 };
int ambientCcolorS = (int)( sin( 0.3 * coordinates[0] + backgroundShift) * 127.0 );
int ambientCcolorC = (int)( cos( 0.3 * coordinates[1] + backgroundShift) * 128.0);
int amberC = (ambientCcolorS + ambientCcolorC + 255) / 2;
NeoPixel.setPixelColor(
led,
NeoPixel.Color(amberC, amberC ,255));
}
}
bool firstIteration = false;
void drawCircle() {
// x y Anteil
byte bitmap[circle_size_corona + 1][circle_size_corona + 1];
float startPositonX = circle_PosX - .5f * (float)circle_size_corona;
float startPositonY = circle_PosY - .5f * (float)circle_size_corona;
int lowerStartX = floor(startPositonX);
int upperStartX = ceil(startPositonX);
int lowerStartY = floor(startPositonY);
int upperStartY = ceil(startPositonY);
float proportionForLowerX = abs(upperStartX - startPositonX);
float proportionForUpperX = 1 - proportionForLowerX;
float proportionForLowerY = abs(upperStartY - startPositonY);
float proportionForUpperY = 1 - proportionForLowerY;
firstIteration = true;
for(byte x = 0; x < circle_size_corona; x++) {
for(byte y = 0; y < circle_size_corona; y++) {
float proportion = 0;
int lowerLedX = lowerStartX + x;
int lowerLedY = lowerStartY + y;
int upperLedX = upperStartX + x;
int upperLedY = upperStartY + y;
if(lowerLedX >= 0 || lowerLedX < num_col
&&
lowerLedY >= 0 || lowerLedY < num_row) {
byte currentX = x;
byte currentY = y;
proportion = proportionForLowerX * proportionForLowerY;
bitmap[currentX][currentY] += (byte)(proportion * 100);
bitmap[currentX][currentY] = min(bitmap[currentX][currentY], (byte)100);
if(lowerLedX == 6 && lowerLedY == 6) {
Serial.print(", x ");
Serial.print(x);
Serial.print(", y ");
Serial.print(y);
Serial.print(", partialProportion ");
Serial.print(proportion);
Serial.print(", newBitmapVal ");
byte newBitmapVal = bitmap[currentX][currentY];
Serial.print(newBitmapVal);
Serial.print(" || ");
}
}
if(upperLedX >= 0 || upperLedX < num_col
&&
lowerLedY >= 0 || lowerLedY < num_row) {
byte currentX = x + 1;
byte currentY = y;
proportion = proportionForUpperX * proportionForLowerY;
bitmap[currentX][currentY] += (byte)(proportion * 100);
bitmap[currentX][currentY] = min(bitmap[currentX][currentY], (byte)100);
if(upperLedX == 6 && lowerLedY == 6) {
Serial.print(", x ");
Serial.print(x);
Serial.print(", y ");
Serial.print(y);
Serial.print(", partialProportion ");
Serial.print(proportion);
Serial.print(", newBitmapVal ");
byte newBitmapVal = bitmap[currentX][currentY];
Serial.print(newBitmapVal);
Serial.print(" || ");
}
}
if(lowerLedX >= 0 || lowerLedX < num_col
&&
upperLedY >= 0 || upperLedY < num_row) {
byte currentX = x;
byte currentY = y + 1;
proportion = proportionForLowerX * proportionForUpperY;
bitmap[currentX][currentY] += (byte)(proportion * 100);
bitmap[currentX][currentY] = min(bitmap[currentX][currentY], (byte)100);
if(lowerLedX == 6 && upperLedY == 6) {
Serial.print(", x ");
Serial.print(x);
Serial.print(", y ");
Serial.print(y);
Serial.print(", partialProportion ");
Serial.print(proportion);
Serial.print(", newBitmapVal ");
byte newBitmapVal = bitmap[currentX][currentY];
Serial.print(newBitmapVal);
Serial.print(" || ");
}
}
if(upperLedX >= 0 || upperLedX < num_col
&&
upperLedY >= 0 || upperLedY < num_row) {
byte currentX = x + 1;
byte currentY = y + 1;
proportion = proportionForUpperX * proportionForUpperY;
bitmap[currentX][currentY] += (byte)(proportion * 100);
bitmap[currentX][currentY] = min(bitmap[currentX][currentY], (byte)100);
bitmap[currentX][currentY] = min(bitmap[currentX][currentY], (byte)100);
if(upperLedX == 6 && upperLedY == 6) {
Serial.print(", x ");
Serial.print(x);
Serial.print(", y ");
Serial.print(y);
Serial.print(", partialProportion ");
Serial.print(proportion);
Serial.print(", newBitmapVal ");
byte newBitmapVal = bitmap[currentX][currentY];
Serial.print(newBitmapVal);
Serial.print(" || ");
}
}
firstIteration = false;
}
}
firstIteration = true;
for(int x = 0; x < circle_size_corona + 1; x++) {
for(int y = 0; y < circle_size_corona + 1; y++) {
int lowerLedX = lowerStartX + x;
int lowerLedY = lowerStartY + y;
int upperLedX = upperStartX + x;
int upperLedY = upperStartY + y;
if(
// firstIteration
lowerLedX == 6 && lowerLedY == 6
||
upperLedX == 6 && lowerLedY == 6) {
Serial.print(", startPositonX ");
Serial.print(startPositonX);
Serial.print(", x ");
Serial.print(x);
Serial.print(", y ");
Serial.print(y);
Serial.print(", lowerLedX ");
Serial.print(lowerLedX);
Serial.print(", lowerLedY ");
Serial.print(lowerLedY);
}
if(lowerLedX >= 0 || lowerLedX < num_col
&&
lowerLedY >= 0 || lowerLedY < num_row) {
setLedColorWithProportion(lowerLedX,lowerLedY, .01f * bitmap[x][y]);
}
firstIteration = false;
}
}
Serial.print(" ");
Serial.println();
}
void setLedColorWithProportion(
int coordX, int coordY,
float proportion)
{
int led = ledByCoordinate(coordX, coordY);
uint32_t ledColor = NeoPixel.getPixelColor(led);
uint8_t partialColor = (uint8_t)((proportion ) * 255.0f );
uint8_t white = (ledColor>>24) & 255;
uint8_t red = (uint8_t)((1.0f - proportion) * ((ledColor>>16) & 255))
+ partialColor;
uint8_t green = (ledColor>>8) & 255;
uint8_t blue = ledColor & 255;
if(
// firstIteration
coordX == 6 && coordY == 6
) {
Serial.print(", prop ");
Serial.print(proportion);
Serial.print(", redValOld ");
Serial.print(((ledColor>>16) & 255));
Serial.print(", redValNew ");
Serial.print(red);
}
ledColor = white;
ledColor = (ledColor<<8) + red;
ledColor = (ledColor<<8) + green;
ledColor = (ledColor<<8) + blue;
NeoPixel.setPixelColor(
led,
ledColor);
}
int ledByCoordinate(byte column, byte row) {
return (row * num_col) + (column);
}
void coordinateByLed(int coordinates[2], int led) {
coordinates[0] = led % num_col;
coordinates[1] = led / num_col;
}
First attempt without bitmap
#include <Adafruit_NeoPixel.h>
#define PIN_NEO_PIXEL 13
#define NUM_PIXELS 400
#define num_row 20
#define num_col 20
#define circle_size_body 4
#define circle_size_border 5
#define circle_size_corona 7
#define DELAY_INTERVAL 100
float circle_PosX = 10;
float circle_PosY = 10;
int circle_direction = 1;
enum eIntersectingPart { None, Body, Border, Corona };
Adafruit_NeoPixel NeoPixel(NUM_PIXELS, PIN_NEO_PIXEL, NEO_GRB + NEO_KHZ800);
void setup()
{
NeoPixel.setBrightness(100);
NeoPixel.begin();
Serial.begin(9600); // set up Serial library at 9600 bps
}
float backgroundShift = 0;
float worldSpeed = .01;
void loop()
{
if(circle_PosY <= 0 && circle_direction < 0
|| circle_PosY >= 10 && circle_direction > 0)
circle_direction *= -1;
circle_PosY += worldSpeed * circle_direction;
circle_PosX += worldSpeed * circle_direction;
// Serial.print("circle_PosX ");
// Serial.print(circle_PosX);
// Serial.print(", circle_PosY ");
// Serial.print(circle_PosY);
NeoPixel.clear();
//Hintergrund setzen
// setBackgroundColor();
//Kreis malen
drawCircle();
// Serial.print("bgShift: ");
// Serial.flush();
NeoPixel.show(); // send the updated pixel colors to the NeoPixel hardware.
// Serial.println(backgroundShift);
backgroundShift += worldSpeed;
//delay(100); // off time
}
uint32_t setBackgroundColor() {
for(int led = 0; led < NUM_PIXELS; led++) {
int coordinates[2];
coordinateByLed(coordinates, led);
byte ambientColors[3] = { 0, 0, 255 };
int ambientCcolorS = (int)( sin( 0.3 * coordinates[0] + backgroundShift) * 127.0 );
int ambientCcolorC = (int)( cos( 0.3 * coordinates[1] + backgroundShift) * 128.0);
int amberC = (ambientCcolorS + ambientCcolorC + 255) / 2;
NeoPixel.setPixelColor(
led,
NeoPixel.Color(amberC, amberC ,255));
}
}
bool firstIteration = false;
void drawCircle() {
float startPositonX = circle_PosX - .5f * (float)circle_size_corona;
float startPositonY = circle_PosY - .5f * (float)circle_size_corona;
int lowerStartX = floor(startPositonX);
int upperStartX = ceil(startPositonX);
int lowerStartY = floor(startPositonY);
int upperStartY = ceil(startPositonY);
float proportionForLowerX = abs(upperStartX - startPositonX);
float proportionForUpperX = 1 - proportionForLowerX;
float proportionForLowerY = abs(upperStartY - startPositonY);
float proportionForUpperY = 1 - proportionForLowerY;
// int endX = lowerStartX + circle_size_corona;
// int endY = lowerStartY + circle_size_corona;
firstIteration = true;
for(int x = 0; x < circle_size_corona; x++) {
for(int y = 0; y < circle_size_corona; y++) {
int lowerLedX = lowerStartX + x;
int lowerLedY = lowerStartY + y;
int upperLedX = upperStartX + x;
int upperLedY = upperStartY + y;
/*if(firstIteration) {
Serial.print(", startPositonX ");
Serial.print(startPositonX);
Serial.print(", x ");
Serial.print(x);
Serial.print(", y ");
Serial.print(y);
Serial.print(", lowerLedX ");
Serial.print(lowerLedX);
Serial.print(", lowerLedY ");
Serial.print(lowerLedY);
}*/
if(lowerLedX >= 0 || lowerLedX < num_col
&&
lowerLedY >= 0 || lowerLedY < num_row) {
setLedColorWithProportion(lowerLedX,lowerLedY, proportionForLowerX * proportionForLowerY);
}
if(upperLedX >= 0 || upperLedX < num_col
&&
lowerLedY >= 0 || lowerLedY < num_row) {
setLedColorWithProportion(upperLedX,lowerLedY, proportionForUpperX * proportionForLowerY);
}
if(lowerLedX >= 0 || lowerLedX < num_col
&&
upperLedY >= 0 || upperLedY < num_row) {
setLedColorWithProportion(lowerLedX,upperLedY, proportionForLowerX * proportionForUpperY);
}
if(upperLedX >= 0 || upperLedX < num_col
&&
upperLedY >= 0 || upperLedY < num_row) {
setLedColorWithProportion(upperLedX,upperLedY, proportionForUpperX * proportionForUpperY);
}
firstIteration = false;
}
}
// Serial.print(" ");
// Serial.println();
}
void setLedColorWithProportion(
int coordX, int coordY,
float proportion)
{
int led = ledByCoordinate(coordX, coordY);
uint32_t ledColor = NeoPixel.getPixelColor(led);
uint8_t partialColor = (uint8_t)((proportion ) * 255.0f );
uint8_t white = (ledColor>>24) & 255;
uint8_t red = (uint8_t)((1.0f - proportion) * ((ledColor>>16) & 255))
+ partialColor;
uint8_t green = (ledColor>>8) & 255;
uint8_t blue = ledColor & 255;
ledColor = white;
ledColor = (ledColor<<8) + red;
ledColor = (ledColor<<8) + green;
ledColor = (ledColor<<8) + blue;
NeoPixel.setPixelColor(
led,
ledColor);
}
int ledByCoordinate(byte column, byte row) {
/*if(firstIteration) {
Serial.print(", column ");
Serial.print(column);
Serial.print(", row ");
Serial.print(row);
Serial.print(", ergebis ");
Serial.print(((row * num_col) + (column)));
}*/
return (row * num_col) + (column);
}
void coordinateByLed(int coordinates[2], int led) {
coordinates[0] = led % num_col;
coordinates[1] = led / num_col;
}
setLedColorWithProportion()
is a quite unconventional way to do alpha compositing: the foreground object is transparent in all channels but red. The usual expectation is for the opacity to be the same for all channels.