Drawing shader consistently regardless of size and position in canvas

Hello. I have custom glsl fragment shader files and am drawing them using rect(). I want the shader to be drawn as if it was an image, which means all the information should be present when drawn, and it should stretch depending on the dimensions passed in rect() and to the shader.

As it stands the shaders are being drawn relative to the canvas. The same pixels in the canvas will always have the same color regardless of the size and position of the rect(), as if the shader was being masked. Changing the size of the canvas stretches the shader.

From what I could find online, passing the dimensions information to the shader and normalizing the pixel values should do it. But the resolution variable is having no effect on the shader whatsoever. What am I missing?

Processing code:

PShader shader;

void setup() {
  size(1080, 1080, P2D);
  shader = loadShader("shader.glsl");
}

void draw() {
  background(0);
  
  shader.set("resolution", mouseX, mouseY);
  
  shader(shader);
  rect(0, 0, mouseX, mouseY);
}

Glsl code:

uniform vec2 resolution;

void main() {
    vec2 uv = gl_FragCoord.xy / resolution;

    vec3 RGB = generateRGB(uv.x, uv.y);

    gl_FragColor = vec4(RGB.x, RGB.y, RGB.z, 1.0);
}

Screenshots of above code:

Desired outcome:

Thanks for the help!

gl_FragCoord.xy gives the window coordinates of the pixel independent of whatever triangle it is drawn from. It’s convenient to use when you want a full-screen fragment shader, but not what you want for arbitrary textured geometry. For that, you need to use texture coordinates. Processing generates vec4 texCoord coordinates for its geometry. For a rect(), they go from 0 to 1 in the xy channels. (I’m not sure what, if anything, is stored in the zw channels.)

PShader shdr;

void setup() {
  size( 800, 800, P2D );
  shdr = new PShader( this, vertSrc, fragSrc );
  noStroke();
}

void draw() {
  background(0);
  shader( shdr );
  noStroke();
  rect( 0, 0, 400, 400+200*sin(0.02*frameCount) );
  translate( 600, 500 );
  rotate( TAU*frameCount/360 );
  rect( -100, -150, 200, 300 );
  resetShader();
}

String[] vertSrc = {"""
#version 330 core
uniform mat4 modelview;
uniform mat4 projection;
in vec4 position;
in vec4 texCoord;
out vec2 uv;
void main() {
  uv = texCoord.xy;
  gl_Position = projection * modelview * position;
}
"""};

String[] fragSrc = {"""
#version 330 core
in vec2 uv;
out vec4 fragColor;
void main() {
  fragColor = vec4( length(uv-0.5) < 0.25 ? vec2(0.) : uv, 0.0, 1.0 );
}
"""};
3 Likes

Awesome, just what I needed! Thank you so much!

Edit: found out that creating a PGraphics and drawing there it’ll behave as wanted as long as it occupies the whole canvas

1 Like