Control the color of the shadow with a Processing filter(BLUR).
In this post, I explore how to overcome a common frustration in Processing: the default black shadow produced by the filter(BLUR) function. Can we make it vibrant? Let's find out.
In my previous article, I experimented with stacking randomly blurred layers. Here is the drawn image:
While the effect was interesting, the "nuance" felt different compared to p5.js's drawingContext. p5.js feels light and airy, while Processing can feel... a bit heavy.
This is the reference image drawn by the p5.js drawingContext.
off / on
— Shunsuke Takawo (@takawo) August 9, 2022
drawingContext.filter = "blur(" + int(random(15)) + "px)" pic.twitter.com/0SvEqQOrvu
The Mystery of the Black Halo
Why do these blurs look so dark? After a helpful tip from @emeen231, I realized the culprit was hiding in plain sight:
出来ました!
— え ͤみ ͫ ͤー ͤん ͛ (@emeen231) September 30, 2022
circle単位でfilter(BLUR, ~);をかけるのではなくPGraphicsごとに実行すると円の周りが黒くなることなく重なってくれます pic.twitter.com/Z4w7qo1fOb
So, where does this black "halo" come from? Looking at my code, a suspect emerged: the background initialization.
p.background(0.0, 0.0);
Here is the whole code.
Click to view the source code
/**
* Stacking the random blur layers.
*
* @author @deconbatch
* @version 0.1
* @license CC0
* Processing 3.5.3
* created 2022.09.23
*/
void setup(){
size(640, 640);
int layerNum = 12; // number of layers
background(0.0);
for (int i = 0; i < layerNum; i++) {
image(
getLayer(
random(10.0) // blur randomly
),
0, 0);
}
}
/**
* getLayer : returns the blured layer.
*/
PGraphics getLayer(float _blur) {
int cNum = 24;
PGraphics p = createGraphics(width, height);
p.beginDraw();
p.background(0.0, 0.0);
p.noStroke();
p.fill(240.0);
for (int i = 0; i < cNum; i++) {
p.circle(
random(width),
random(height),
random(60.0)
);
}
p.filter(BLUR, _blur);
p.endDraw();
return p;
}
I used transparent background for stacking the layers. And the brightness of the background was zero which is black. Even with alpha set to zero, the RGB channels are still 0,0,0. When the blur filter spreads these pixels, that underlying black bleeds into the edges of your shapes.
Let's increase the brightness value on trial.
p.background(240.0, 0.0);
The white shadow! This shows that transparent doesn't mean empty.
Tinting the Atmosphere: Background Color as a Glow
What happens if we change the "transparent" color? I tried setting a blue but transparent background: p.background(64.0, 128.0, 255.0, 0.0);. The result? A clean, ethereal blue glow.
p.background(64.0, 128.0, 255.0, 0.0);
How about the pink background?
p.background(255.0, 128.0, 222.0, 0.0);
It's clear that the background's RGB values dictate the tint of the blur.
Random background color on each layer produces the image like this.
p.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
p.background(random(210.0, 360.0), 80.0, 90.0, 0.0);
Can I Change the Color of the Part of a Shadow?
Now I can control the shadow color as one in the whole canvas. Then, can I control the color in each part of the canvas?
Encountering Unexpected Artifacts
For example, I wrote the code below instead of p.background(). It separates the canvas into four parts that have a different colors.
int div = 2;
p.blendMode(REPLACE);
p.noStroke();
for (int x = 0; x < div; x++) {
for (int y = 0; y < div; y++) {
float rw = width / div;
float rh = height / div;
p.fill(
(x * 60.0 + y * 150.0) % 360.0,
80.0,
90.0,
0.0
);
p.rect(x * rw, y * rh, rw, rh);
}
}
p.blendMode(REPLACE); is the key. It draws a image like this.
Yes! That's... No. Something is wrong.
You can see the left side of each rectangle has a black shadow. When I remove the transparency, the whole part of the rectangle has a color like this. So it is not the failure of painting colors.
You can see the problem well when I separate the canvas into 64 parts and set the circle color black.
I'm afraid the color value does not affect to the left side of each rectangle.
The last resort.
I've not been able to resolve this problem. My last resort is to paint the rectangles with a transparent value of 1.0 instead of 0.0.
By using a nearly-invisible alpha (1.0), we "anchor" the intended color to the pixels without sacrificing perceived transparency.
Embracing the "Handmade" Glitches of Processing
I may disappoint a little if the program does not work as expected. But I love problems like this also. That's because I feel Processing's handmade taste, not the ready-made practical product.
In conclusion, I'll show you the code that draws colorful shadows.
/**
* Random colorful shadows
*
* @author @deconbatch
* @version 0.1
* @license CC0
* Processing 3.5.3
* created 2022.10.08
*/
void setup(){
size(640, 640);
smooth();
int layerNum = 12; // number of the layers
background(255.0);
blendMode(SUBTRACT);
for (int i = 0; i < layerNum; i++) {
image(
getLayer(
random(10.0) // random blur
),
0, 0);
}
}
/**
* getLayer : return _blur value blured layer
*/
PGraphics getLayer(float _blur) {
PGraphics p = createGraphics(width, height);
p.beginDraw();
p.colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
// random color matrix
int div = 8;
p.blendMode(REPLACE);
p.noStroke();
for (int x = 0; x < div; x++) {
for (int y = 0; y < div; y++) {
int rw = round(width / div);
int rh = round(height / div);
int rx = x * rw;
int ry = y * rh;
p.fill(
random(360.0),
90.0,
80.0,
1.0
);
p.rect(rx, ry, rw, rh);
}
}
// random located circles
int cNum = 12;
p.blendMode(BLEND);
p.fill(0.0, 0.0, 0.0, 100.0);
for (int i = 0; i < cNum; i++) {
p.circle(
random(width),
random(height),
pow(random(9.0), 2)
);
}
p.filter(BLUR, _blur);
p.endDraw();
return p;
}
For reference.
My Processing version was 'Processing 3.5.3 on Linux'.
When I tried with the 'Processing 4.0.1 on Linux' the right side and the bottom of the rectangles had a black shadow.
Software isn't always perfect. Between Processing 3.5.3 and 4.0.1, the way filters handle edges seems to have shifted, creating new "glitches" or artifacts. While some might find this frustrating, I love it. It gives Processing a "handmade" feel—like working with physical materials that have their own quirks and personality.














