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;
}