Shaders: Drawing layers on top of each other

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.

1 Like