Weird graphical glitches when switching webgl layer to be a separate pgraphics

p5.js Web Editor << so i have this sketch for sort of a simple 3d game (wasd to move)

it works, but i want to draw the 3d scene to a separate pgraphics object, so that i can draw 2d stuff over the top. so the canvas will use the default renderer, (not sure what the default renderer is called in p5js) but the ‘scene’ uses webgl. then i’m calling image(scene,0,0) to draw it to the canvas.

p5.js Web Editor << this is my attempt.

it almost works, but after the first frame, im getting a lot of glitchy output, things stop drawing properly, i’m not sure what’s the correct way to do this

i’ve made some progress. I wasn’t calling clear() on the webGL buffer. I can prevent some of the graphical problems by calling clear() each frame, but this causes a significant hit to performance. and the color output from image() is still wrong – is there a better way to do this?

1 Like

i think this will work: im going to draw two canvases, with one positioned over the top of the other, with just the bottom canvas using WEBGL. then call clear() rather than background() on the top canvas.

here’s a working example

I think some of the problem might be caused because the two canvases are refreshed at different times. A simpler solution would be to mix 3D and 2D on a single WEBGL canvas.

The sketch below demonstrates how to to this. The only complex code is in the draw2D method which you can totally ignore, just put your 2D code where shown. Do not use background in draw2D() otherwise you will erase the 3D part.

function setup() {
  p5c = createCanvas(710, 400, WEBGL);
  px = 100;  dx = -1;
  py = 50;  dy = 1;
}

function draw() {
  background(255, 230, 255);
  draw3D();  // draw 3D before 2D
  draw2D();  // now draw 2D overlay
}

function draw2D() {
  push();
  let gl = p5c.drawingContext;
  let w = p5c.width, h = p5c.height, d = Number.MAX_VALUE;
  gl.flush();
  let mvMatrix = p5c.uMVMatrix.copy();
  let pMatrix = p5c.uPMatrix.copy();
  gl.disable(gl.DEPTH_TEST);
  p5c.resetMatrix();
  p5c._curCamera.ortho(0, w, -h, 0, -d, d);

  // ##############################################################################
  // Start 2D sketch code

  fill (0, 255, 0, 128);
  if (px > w - 200 || px <= 0) dx *= -1;
  px = px + 3 * dx;
  rect(px, 60, 200, 150);
  if (py >= height || py < 0) dy *= -1;
  py = py + 3 * dy;
  fill (0, 0, 255, 128);
  ellipse(200, py, 70, 110);

  // End 2D sketch code
  // ##############################################################################

  gl.flush();
  p5c.uMVMatrix.set(mvMatrix);
  p5c.uPMatrix.set(pMatrix);
  gl.enable(gl.DEPTH_TEST);
  pop();
}

function draw3D() {
  push();
  rotateY(frameCount * 0.0002);
  fill(255, 255, 200);
  strokeWeight(0.5);
  for (let j = 0; j < 5; j++) {
    push();
    for (let i = 0; i < 80; i++) {
      translate(
        sin(frameCount * 0.0002 + j) * 100,
        sin(frameCount * 0.0002 + j) * 100,
        i * 0.1
        );
      rotateZ(frameCount * 0.0004);
      push();
      sphere(8, 6, 4);
      pop();
    }
    pop();
  }
  pop();
}
1 Like