How can I glow the thing on the screen shining from the first?
There is a knack in making glow effect with the 'Processing' or the 'p5.js'.
I'll describe specifically how to make a glow effect with the code. I'll write a code for explanation with the 'p5.js'. And I'll show you the advanced example animation code with the 'Processing'.
The computer screen is shining in the first place...
Your creative coding code usually outputs the result on the computer screen. And the screen shines itself so your creative coding code's result is shining from the very first.
The color on the screen is made of the three primary colors of light (red, green, and blue).
Red, Green, and Blue = RGB
https://en.wikipedia.org/wiki/RGB_color_model
It's shining too but we don't feel it is shining.
How to make it glow.
Then, how can I glow the thing on the screen?
One of the easy ways in Processing/p5.js is using 'blendMode(ADD)'. The 'blendMode(ADD)' do addition of colors as its name suggests.
For example, this code draws circles of red, green, and blue color.
const w = 640;
const h = w;
function setup() {
createCanvas(w, h);
colorMode(HSB, 360, 100, 100, 100);
noLoop();
background(0, 0, 0, 100);
noStroke();
// Red
fill(0, 90, 30, 100);
circle(w * 0.4, h * 0.4, w * 0.5);
// Green
fill(120, 90, 30, 100);
circle(w * 0.6, h * 0.4, w * 0.5);
// Blue
fill(240, 90, 30, 100);
circle(w * 0.5, h * 0.6, w * 0.5);
}
It ordinally results.
I put the 'blendMode(ADD)' before drawing, then it does the addition of red, green, and blue colors. And the result is the picture of three primary colors of light I showed before.
background(0, 0, 0, 100);
noStroke();
blendMode(ADD);
// Red
Red + Green = Yellow, Red + Green + Blue = White
If you repeat drawing with low brightness like this code, it creates the effect "Oh! It's glowing!".
const w = 640;
const h = w;
function setup() {
createCanvas(w, h);
colorMode(HSB, 360, 100, 100, 100);
noLoop();
frameRate(15);
background(0, 0, 0, 100);
noStroke();
blendMode(ADD);
for (let r = 0.0; r < 0.5; r += 0.01) {
// Red
fill(0, 90, 5, 100);
circle(w * 0.4, h * 0.4, w * r);
// Green
fill(120, 90, 5, 100);
circle(w * 0.6, h * 0.4, w * r);
// Blue
fill(240, 90, 5, 100);
circle(w * 0.5, h * 0.6, w * r);
}
}
It's an animation of drawing over and over.
光の三原色に灼かれる悦びを噛み締めよ!🌞#p5js #creativecoding pic.twitter.com/wwuHpSGYAU
— deconbatch (@deconbatch) January 10, 2022
More light!
When you repeat drawing, the hue, saturation, and brightness values act upon the way of glowing.
※Hue, Saturation, and Brightness
The default color mode of Processing/p5.js is 'RGB'. It's hard to control the hue, saturation, and brightness values individually with the 'RGB' color mode. So I recommend using the 'HSB' color mode in this situation.
colorMode(HSB, 360, 100, 100, 100);
For example, it looks different even you just change the saturation value.
This is the animation example of the blue and bluish-purple circles. It changes the saturation value of the bluish-purple circle only.
これはアニメーションではありません。
— deconbatch (@deconbatch) January 10, 2022
今、あなたのモニターが焼きついているところです。😈#p5js #creativecoding pic.twitter.com/lOLcCCgrHw
100 + 0 = 100
The 'blendMode(ADD)' means addition. So you can't paint with black (brightness = 0). The more precise, it paints with 'brightness = 0' but it is the same result when you add zero to some.
If you want to paint with 'background()' every frame, you should switch the blend mode to 'blendMode(BLEND)'. I often forget about it and I see the white outed screen.
I'll give an example of changing saturation value and switching the blend mode. You can see how the effect works when you comment out the 'blendMode(BLEND)'.
const w = 640;
const h = w;
function setup() {
createCanvas(w, h);
colorMode(HSB, 360, 100, 100, 100);
}
function draw() {
let frmRatio = map(frameCount % 120, 0, 120, 1.0, 0.0);
blendMode(BLEND);
background(240, 100, 30, 100);
noStroke();
// sun
blendMode(ADD);
for (let r = 0.0; r < 1.0; r += 0.01) {
fill(280, frmRatio * 100, (1.0 - r) * 5, 100);
circle(w * 0.6, h * 0.5, w * r);
}
// planet
blendMode(BLEND);
fill(240, 100, frmRatio * 80, 100);
circle(w * 0.5, h, w * 0.8);
}
時は来たれり👼#p5js #creativecoding pic.twitter.com/sMJV909RYo
— deconbatch (@deconbatch) January 10, 2022
ADD and SCREEN
There is the 'blendMode(SCREEN)' similar to the 'blendMode(ADD)'.
'SCREEN' brings mild effect than 'ADD'.
Recap of the points on how to make it glow.
Points of the glow effect.
Points of devising.
The example code of 'p5.js'.
I wrote an example code of a glowing animation using 'blendMode(SCREEN)' in p5.js (JavaScript). The title is 'City lights'. Please run it and enjoy how it shows.
Please feel free to use this example code under the terms of the GPL.
// City Lights
const w = 720;
const h = 480;
const blobNum = 20;
function setup() {
createCanvas(w, h);
colorMode(HSB, 360, 100, 100, 100);
frameRate(15);
}
function draw() {
let frmRatio = map(frameCount % 120, 0, 120, 0, 1);
blendMode(BLEND);
background(240, 100, 20, 100);
for (let i = 0; i < blobNum; i++) {
let bTime = sin(PI * ((frmRatio + noise(10, i)) % 1));
let bHue = (360 * frmRatio + noise(20, i) * 240) % 360;
blob(i / blobNum, noise(30, i), bTime, bHue);
}
}
function blob(_x, _y, _t, _hue) {
blendMode(SCREEN);
noStroke();
for (let r = 0.0; r < 0.2; r += 0.002) {
fill(_hue, 100, r * 3, 100);
circle(_x * w, _y * h, w * r * 0.5);
fill(_hue, _t * 100, (1.0 - r) * 3, 100);
circle(_x * w, _y * h, w * r);
}
}
/*
Copyright (C) 2022- deconbatch
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
The example code of 'Processing'.
This example code shows sparkling lights rather than glowing. Please feel free to use this example code under the terms of the GPL.
/**
* Light Years.
* simple animation using Node-Garden technique.
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2022.01.15
*/
void setup() {
size(720, 480, P2D);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
smooth();
noLoop();
}
void draw() {
int frmRate = 30;
int cycleSec = 8;
int cycleMax = 3;
int nodeNum = 15;
float orbitBase = min(width, height) * 0.25;
float rangeS = orbitBase * 0.2;
float rangeL = orbitBase * 0.4;
float hueBase = random(360.0);
// nodes clusters
ArrayList<Cluster> clusters = getClusters(nodeNum, orbitBase);
int clusterMax = clusters.size();
// nodes
ArrayList<Node> nodes = getNodes(clusterMax * nodeNum, orbitBase);
int nodeMax = nodes.size();
// easing functions
ArrayList<Ease> easing = new ArrayList<Ease>();
easing.add(new Four());
easing.add(new Quadratic());
easing.add(new Cos());
easing.add(new Pow());
easing.add(new Cubic());
int easeMax = easing.size();
int frmMax = frmRate * cycleSec * cycleMax;
int frmCycleMax = frmRate * cycleSec;
for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
int cycleCnt = frmCnt / frmCycleMax;
float frmRatio = map(frmCnt % frmCycleMax, 0, frmCycleMax, 0.0, 1.0);
// animate calculation
for (int clusterCnt = 0; clusterCnt < clusterMax; clusterCnt++) {
float waveRatio = easing.get((cycleCnt + clusterCnt) % easeMax).ease(frmRatio);
Cluster cluster = clusters.get(clusterCnt);
for (int idx = cluster.nodeFrom; idx < cluster.nodeTo; idx++) {
nodes.get(idx).animate(waveRatio, frmRatio, cluster.x, cluster.y);
}
}
blendMode(BLEND);
background(0.0, 0.0, 0.0, 100.0);
// draw
blendMode(ADD);
for (int clusterCnt = 0; clusterCnt < clusterMax; clusterCnt++) {
float clusterRatio = map(clusterCnt, 0, clusterMax, 0.0, 1.0);
float rangeWave = abs(sin(PI * (frmRatio + clusterRatio)));
// lines between clusters
Cluster cluster = clusters.get(clusterCnt);
stroke(cluster.hueVal % 360.0, 90.0, 30.0, 100.0 * rangeWave);
for (Cluster c : clusters) {
float d = dist(cluster.x, cluster.y, c.x, c.y);
strokeWeight(d / orbitBase);
if (d < orbitBase * 1.5) {
line(cluster.x, cluster.y, c.x, c.y);
}
}
for (int i = cluster.nodeFrom; i < cluster.nodeTo; i++) {
Node n = nodes.get(i);
// nodes
noStroke();
fill(cluster.hueVal % 360.0, 80.0, 70.0, 100.0);
ellipse(n.x, n.y, 3.0, 3.0);
// lines between nodes
for (int j = i + 1; j < nodeMax; j++) {
Node m = nodes.get(j);
float d = dist(n.x, n.y, m.x, m.y);
if (d < rangeL * rangeWave && d > rangeS * rangeWave) {
stroke(cluster.hueVal % 360.0, 80.0, 40.0, 100.0);
strokeWeight(2);
line(n.x, n.y, m.x, m.y);
noStroke();
fill((cluster.hueVal + 300.0) % 360.0, 40.0, 10.0, 100.0);
ellipse(n.x, n.y, 8.0, 8.0);
fill((cluster.hueVal + 30.0 + 60.0 * (d - rangeS) / (rangeL - rangeS)) % 360.0, 40.0, 3.0, 100.0);
ellipse(m.x, m.y, 15.0, 15.0);
}
}
}
}
saveFrame("frames/" + String.format("%04d", frmCnt) + ".png");
}
exit();
}
/**
* getClusters : returns whole clusters.
*/
ArrayList<Cluster> getClusters(int _nodeNum, float _radius) {
int tryMax = 100;
float spacing = _radius * 0.75;
float hueBase = random(360.0);
ArrayList<Cluster> clusters = new ArrayList<Cluster>();
// circle packing
int cnt = 0;
for (int i = 0; i < tryMax; i++) {
int x = floor(random(spacing, width) - spacing * 0.5);
int y = floor(random(spacing, height) - spacing * 0.5);
boolean hit = false;
for (Cluster c : clusters) {
float d = dist(x, y, c.x, c.y);
if (d < spacing) {
hit = true;
break;
}
}
if (!hit) {
clusters.add(new Cluster(cnt++, _nodeNum, x, y, hueBase + cnt * 90.0));
}
}
return clusters;
}
/**
* getNodes : returns whole nodes.
*/
ArrayList<Node> getNodes(int _cnt, float _radius) {
ArrayList<Node> nodes = new ArrayList<Node>();
for (int i = 0; i < _cnt; i++) {
float r = random(_radius);
float t = random(TWO_PI);
nodes.add(new Node(
r,
t
));
}
return nodes;
}
/**
* Node : hold node.
*/
public class Node {
public float x, y; // coordinate of node
private float r, t; // radius and theta to calculate the x, y
private float oR, oT; // original radius and theta
private float tPhase; // random phase of theta
Node(float _oR, float _oT) {
oR = _oR;
oT = _oT;
tPhase = random(PI);
}
public void animate(float _rRatio, float _tRatio, float _oX, float _oY) {
r = oR * abs(sin(TWO_PI * _rRatio + tPhase));
t = oT + TWO_PI * ((_tRatio + sin(tPhase)) % 1.0);
x = _oX + r * cos(t);
y = _oY + r * sin(t);
}
}
/**
* Cluster : hold cluster.
*/
public class Cluster {
public int nodeFrom, nodeTo; // number of nodes belong to the cluster
public float x, y; // coordinate of node
public float hueVal; // hue value of node
Cluster(int _no, int _nodeNum, float _x, float _y, float _hue) {
nodeFrom = _no * _nodeNum;
nodeTo = nodeFrom + _nodeNum - 1;
x = _x;
y = _y;
hueVal = _hue;
}
}
/**
* Ease : hold easing functions.
*/
public interface Ease {
public float ease(float _t);
}
public class Cos implements Ease {
public float ease(float _t) {
return 1.0 - cos(HALF_PI * _t);
}
}
public class Quadratic implements Ease {
public float ease(float _t) {
_t *= 2.0;
if (_t < 1.0) {
return pow(_t, 2) / 2.0;
}
_t -= 1.0;
return -(_t * (_t - 2) - 1.0) / 2.0;
}
}
public class Cubic implements Ease {
public float ease(float _t) {
_t *= 2.0;
if (_t < 1.0) {
return pow(_t, 3) / 2.0;
}
_t -= 2.0;
return (pow(_t, 3) + 2.0) / 2.0;
}
}
public class Four implements Ease {
public float ease(float _t) {
return 1.0 - pow(1.0 - _t, 4);
}
}
public class Pow implements Ease {
public float ease(float _t) {
return pow(_t, 2);
}
}
/*
Copyright (C) 2022- deconbatch
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/