Chaining GLSL frag shaders

Hello,

I’m attempting to chain some very simple fragment shaders and I’m unsure what I’m doing wrong. I’m following the concept outlined in the readme posted by cansik in this bloom filter:

https://github.com/cansik/processing-bloom-filter

There are a couple of issues here:

1 - The image is upside down. I have no idea why this would be, since I’m not doing any transforms. I would suspect it’s because of some coordinate system snafu, but I’m unsure where I went wrong.
2 - The brightness control (which is earlier in the chain) does not work at all.

If I set them up individually, they work fine, but it seems to be the chaining that does not work. Any help would be much appreciated.

Here is my Processing code:

PGraphics imageView;
PImage previewImage;

PGraphics canvas;
PGraphics brightness_pass;
PGraphics contrast_pass;

PShader brightness_shader;
PShader contrast_shader;

float adjust_brightness = 0.0;
float adjust_contrast = 1.0;

void setup() {
  size(512, 512, P2D);

  imageView = createGraphics(width, height, P2D);
  previewImage = loadImage("mandrill.png");

  // --Set-up-filter-chain-with-PGraphics--
  canvas = createGraphics(previewImage.width, previewImage.height, P2D);
  brightness_pass = createGraphics(previewImage.width, previewImage.height, P2D);
  contrast_pass = createGraphics(previewImage.width, previewImage.height, P2D);

  // --Set-up-shaders--
  brightness_shader = loadShader("brightness.glsl");
  brightness_shader.set("srcTex", previewImage);
  contrast_shader = loadShader("contrast.glsl");
  contrast_shader.set("srcTex", previewImage);
}

void draw() {
  background(0);

  adjust_brightness = map(mouseX, 0, width, -1.0, 1.0);
  adjust_contrast = map(mouseY, 0, height, 0.0, 4.0);

  canvas.beginDraw();
  canvas.image(previewImage, 0, 0);
  canvas.endDraw();

  brightness_pass.beginDraw();
  brightness_shader.set("brightness", adjust_brightness);
  brightness_pass.shader(brightness_shader);
  brightness_pass.image(canvas, 0, 0);
  brightness_pass.endDraw();

  contrast_pass.beginDraw();
  contrast_shader.set("contrast", adjust_contrast);
  contrast_pass.shader(contrast_shader);
  contrast_pass.image(brightness_pass, 0, 0);
  contrast_pass.endDraw();

  imageView.beginDraw();
  imageView.imageMode(CENTER);
  imageView.image(contrast_pass, imageView.width/2, imageView.height/2);
  imageView.endDraw();

  image(imageView, 0, 0);
}

And here are my simple frag shaders. Brightness:

varying vec4 vertTexCoord;

uniform sampler2D srcTex;
uniform float brightness;

void main() {
    lowp vec4 textureColor = texture2D(srcTex, vertTexCoord.xy);

    gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);

 }

Contrast:

varying vec4 vertTexCoord;

uniform sampler2D srcTex;
uniform float contrast;

void main()
{
    lowp vec4 textureColor = texture2D(srcTex, vertTexCoord.xy);
    
    highp float contrastScaled = 4.0 * contrast;
    
    gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrastScaled + vec3(0.5)), textureColor.a);
}

Adam Ferriss was kind enough to help me here, so I thought I’d pay it forward and share the solution to everyone.

Problem 1 - The image is upside down:
Applying shaders to images doesn’t quite work here. What I really needed to do was apply a texture to a rectangle. This fixes the orientation problem.

OpenGL will flip the image with each pass. I have two passes here, so with the corrected code it ends up being OK. If you have an odd number of passes, you can simply store the texture coordinates, vertTexCoord, in a new vec2 within the last fragment shader like this:

    vec2 uv = vertTexCoord.xy;
    uv.y = 1.0 - uv.y;

Use uv.xy instead of vertTexCoord.xy after this in your code and the orientation will be corrected. You could also create a shader for flipping, or just use a transform.

Problem 2 - Only the last adjustment works:
The chaining will not work because I needed to pass the textures using set from shader to shader in the draw cycle. Previously I was doing it in setup.

It’s a simple fix that makes sense. Here’s the code. And thanks again Adam!

PGraphics imageView;
PImage previewImage;

PGraphics canvas;
PGraphics brightness_pass;
PGraphics contrast_pass;

PShader brightness_shader;
PShader contrast_shader;

float adjust_brightness = 0.0;
float adjust_contrast = 1.0;

void setup() {
  size(512, 512, P2D);

  imageView = createGraphics(width, height, P2D);
  previewImage = loadImage("mandrill.png");

  // --Set-up-filter-chain-with-PGraphics--
  canvas = createGraphics(previewImage.width, previewImage.height, P2D);
  brightness_pass = createGraphics(previewImage.width, previewImage.height, P2D);
  contrast_pass = createGraphics(previewImage.width, previewImage.height, P2D);

  // --Set-up-shaders--
  brightness_shader = loadShader("brightness.glsl");
  contrast_shader = loadShader("contrast.glsl");
}

void draw() {
  background(0);

  adjust_brightness = map(mouseX, 0, width, -1.0, 1.0);
  adjust_contrast = map(mouseY, 0, height, 0.0, 4.0);

  canvas.beginDraw();
  canvas.image(previewImage, 0, 0);
  canvas.endDraw();

  brightness_pass.beginDraw();
  brightness_pass.shader(brightness_shader);
  brightness_shader.set("brightness", adjust_brightness);
  brightness_shader.set("srcTex", canvas);
  brightness_pass.rect(0, 0, brightness_pass.width, brightness_pass.height);
  brightness_pass.endDraw();

  contrast_pass.beginDraw();
  contrast_shader.set("contrast", adjust_contrast);
  contrast_pass.shader(contrast_shader);
  contrast_shader.set("srcTex", brightness_pass);
  contrast_pass.rect(0, 0, contrast_pass.width, contrast_pass.height);
  contrast_pass.endDraw();

  imageView.beginDraw();
  imageView.imageMode(CENTER);
  imageView.image(contrast_pass, imageView.width/2, imageView.height/2);
  imageView.endDraw();

  image(imageView, 0, 0);
}