Same shader, multiple graphics?

Is it possible for more than one graphics object to use the same shader? In this sketch here, I would expect two squares to be drawn, a yellow one on the left and a blue on the right, but only the yellow one appears:

As far as I can tell, the only way to see both squares is to draw them both with the same graphics object.

Also, sub-question, is this really the only way to do this? Why can’t I use the rect(x, y, w, h) function to define where a rectangle is drawn and how large it should be? It seems that the numbers I pass into that function are totally irrelevant when I use a shader. Have I always been doing something wrong? I would certainly have guessed so, but looking at everyone else’s code, it seems that this is the only way to do it.

Because of the way WebGL works, each p5.Shader can only be used with the first p5.Graphics that uses it (because this performs compilation). Here’s a working version that simply creates two separate p5.Shaders.

let s0, s1, target0, target1;

function preload() {
  s0 = loadShader('basic.vert', 'SolidColor.frag');
  s1 = loadShader('basic.vert', 'SolidColor.frag');
}

function setup() {
  createCanvas(400, 400);
  
  target0 = createGraphics(100, 100, WEBGL);
  target1 = createGraphics(100, 100, WEBGL);
  
  target0.shader(s0);
  s0.setUniform("uColor", [1, 1, 0]);
  target0.rect(0, 0, 0, 0);
  
  target1.shader(s1);
  s1.setUniform("uColor", [0, 0, 1]);
  target1.rect(0, 0, 0, 0);
  
  background(40);
  image(target0, 50, 150);
  image(target1, 250, 150);
}

Regarding the behavior of shaders with the rect() function, this is because of the content of your vertex shader. The vertex coordinates passed to the shader are not in screen space, they are in model space, and several transforms need to be applied to have the pixels rendered by the shader correspond to the position of the vertices of your geometry:

// Transformation matrices
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;

attribute vec3 aPosition;
// P5 provides us with texture coordinates for most shapes
attribute vec2 aTexCoord;

// This is a varying variable, which in shader terms means that it will be passed from the vertex shader to the fragment shader
varying vec2 vTexCoord;

void main() {
  // Copy the texcoord attributes into the varying variable
  vTexCoord = aTexCoord;

  vec4 viewModelPosition = uModelViewMatrix * vec4(aPosition, 1.0);
  gl_Position = uProjectionMatrix * viewModelPosition;
}
2 Likes

Thanks so much for your reply, this was very helpful.