P5.js GLSL Shaders on Retina Display

I’ve been playing around with GLSL Shaders and was trying out a few P5.js examples on my Mac. I couldn’t figure out why my results weren’t looking like the examples.

The following is the “Hello, world” of shaders. It simply renders a gradient from black to red smoothly across the canvas.

let header =
  'precision highp float;';

// the vertex shader is called for each vertex
let vs =
  header +
  'attribute vec3 aPosition;' +
  'void main() {' +
  '  vec4 positionVec4 = vec4(aPosition, 1.0);' +
  '  positionVec4.xy = positionVec4.xy * 2.0 - 1.0;' + // Correct for GL offset bug.
  '  gl_Position = positionVec4;' +

// the fragment shader is called for each pixel
let fs =
  header +
  'uniform vec2 u_resolution;' +
  'void main() {' +
  '  vec2 st = gl_FragCoord.xy/u_resolution.xy;' +
  '  gl_FragColor = vec4(st.x,st.y,0.0,1.0);' + 

let myShade;
function setup() {
  createCanvas(100, 100, WEBGL); // (0,0) is center
  //pixelDensity(1);  // <-- Uncomment to fix scaling.

  // create and initialize the shader
  myShade = createShader(vs, fs);

function draw() {
  myShade.setUniform("u_resolution", [width, height]);
  rect(-40, -40, 80, 80);

Unfortunately when I run this example on my Mac the gradient stops halfway across the canvas.

That’s not right. It’s not supposed to be completely red until the right edge.

The problem is that by default there’s pixel scaling because of the Retina display which causes the pixel math to be incorrect. The solution is to specify the pixelDensity in the setup function. If the pixel density is set to 1, the shader works as expected.

Set pixelDensity(1) in the script setup to fix the shader scaling problem.