If you use blendMode(ADD)
and darken the background image a little, you can use the blur shader if you render the planes to a separate PGraphics
and then just draw it on top.
int N = 256;
PImage bg;
PGraphics dots;
PShader blurShdr;
void setup() {
size( 1000, 1000, P2D );
colorMode( HSB, 1, 1, 1, 1 );
background(0);
bg = createImage( width, height, ARGB );
bg.loadPixels();
for( int j=0; j<height; j++ )
for( int i=0; i<width; i++ ) {
float h = (noise( i*0.01, j*0.01 ) - 0.5) * 1.2;
bg.pixels[ j*width+i ] = h<0 ? color(0.66, 0.7, 0.6+h) : color(0.33, 0.7, 0.6-h);
}
bg.updatePixels();
dots = createGraphics( width, height, P2D );
dots.beginDraw();
dots.colorMode( HSB, 1, 1, 1, 1 );
dots.noStroke();
dots.background( 0 );
dots.endDraw();
blurShdr = new PShader( this, blurVertSrc, blurFragSrc );
frameRate(30);
}
PVector nextPos( float u, float t ) {
t *= 0.5;
float r = 2+sin(TAU*(21.17*u+2.32*t+0.1*sin(TAU*(23.421*u+5.23*t))));
return new PVector( r*sin(TAU*(u+t)), r*cos(TAU*(u+t)));
}
void draw() {
image( bg, 0, 0 );
dots.beginDraw();
dots.filter( blurShdr );
dots.translate( width/2, height/2 );
float w = dots.width/6.0;
for( int i=0; i<N; i++ ) {
float u = 1.0*i/N;
dots.strokeWeight( w*(0.03+0.02*sin(TAU*17.9*u)) );
dots.stroke( 87.618*u%1, 0.7, 1 );
PVector p0 = nextPos( u, frameCount/500.0 );
PVector p1 = nextPos( u, (frameCount+1)/500.0 );
dots.line( w*p0.x, w*p0.y, w*p1.x, w*p1.y );
}
dots.endDraw();
blendMode(ADD);
image(dots, 0, 0);
blendMode(BLEND);
}
String[] blurVertSrc = {"""
#version 330 core
uniform mat4 modelview;
uniform mat4 projection;
in vec4 position;
in vec4 texCoord;
out vec2 uv;
void main() {
uv = texCoord.xy;
uv.y = 1.0 - uv.y;
gl_Position = projection * modelview * position;
}
"""};
String[] blurFragSrc = {"""
#version 330 core
uniform sampler2D ppixels;
in vec2 uv;
out vec4 fragColor;
float N = 6, R = 7.9;
void main() {
vec2 inc = vec2(1.0)/textureSize( ppixels, 0 ).xy;
vec3 col = vec3(0.);
float sum = 0.;
for( float j=-N; j<=N; j++ )
for( float i=-N; i<=N; i++ ) {
vec2 offs = vec2( i, j );
float len = length( offs );
if( len <= R ) {
float w = 1.-pow(len/R, 1.0);
col += texture( ppixels, uv+inc*offs ).rgb * w;
sum += w;
}
}
col /= sum;
col *= 0.98;
fragColor = vec4( col, 1.0 );
}
"""};
As to learning, no, I don’t know of any particularly good single resource. I learned a lot about shaders and Processing from browsing shadertoy.com and also vertexshaderart.com, reading through https://iquilezles.org/, various sites and youtube series teaching OpenGL, browsing the Processing source on github, and years of reading people’s solutions here on the forum.