如何防止WebGL在每次绘制框架时清洁画布

时间:2019-03-25 16:07:04

标签: javascript webgl

我试图在一个画布上显示来自不同流的多个帧,使用视口并在我必须渲染的每个帧上调用draw函数。我要复制的是仅使用一个画布和一个webgl上下文的摄像机视频墙。问题在于,每当我将一个框架渲染到特定的视口中,然后我之前在其他视口中渲染的其他框架都消失了。

我什至试图将webgl上下文设置中的“ preserveDrawingBuffer”属性设置为true,但是并没有解决。

遵循我正在使用的代码:

<header class="header">
  <div class="left">variable content</div>
  <div class="middle">variable content</div>
  <div class="right">variable content which happens to be very long</div>
</header>

有没有一种方法可以只更新特定的视口而不清理整个上下文?

谢谢

1 个答案:

答案 0 :(得分:1)

您需要打开剪刀测试并设置剪刀矩形

gl.enable(gl.SCISSOR_TEST);
gl.scissor(x, y, width, height);

示例:

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');

const vs = `
attribute vec4 position;
uniform mat4 matrix;
void main() {
  gl_Position = matrix * position;
}
`;
const fs = `
precision mediump float;
uniform vec4 color;
void main() {
  gl_FragColor = color;
}
`;

// compiles shaders, links program, looks up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

// calls gl.createBuffer, gl.bindBuffer, gl.bufferData
const bufferInfo = twgl.primitives.createCylinderBufferInfo(gl, 1, 1, 24, 1);

const scenes = [
  { 
     viewport: [0, 0, 150, 150],
     xRot: 0, 
     zRot: 0, 
     bg: [1, 0, 0, 1], 
     color: [0, 1, 1, 1],
  },
  { 
     viewport: [150, 0, 150, 50],
     xRot: Math.PI * .5, 
     zRot: 0, 
     bg: [0, 1, 0, 1], 
     color: [1, 0, 1, 1],
  },
  { 
     viewport: [150, 50, 150, 100],
     xRot: 0, 
     zRot: Math.PI * 0.25, 
     bg: [0, 0, 1, 1], 
     color: [1, 1, 0, 1],
  },
];

function render(time) {
  time *= 0.001;
 
  gl.enable(gl.SCISSOR_TEST);

  scenes.forEach((scene, ndx) => {
    gl.viewport(...scene.viewport);
    gl.scissor(...scene.viewport);
    
    gl.clearColor(...scene.bg);
    gl.clear(gl.COLOR_BUFFER_BIT);

    const fov = Math.PI * 0.25;
    const aspect = scene.viewport[2] / scene.viewport[3];
    const near = 0.1;
    const far = 10;
    const matrix = m4.perspective(fov, aspect, near, far);
    m4.translate(matrix, [Math.sin(time + ndx), 0, -4], matrix);
    m4.rotateX(matrix, scene.xRot, matrix);
    m4.rotateZ(matrix, scene.zRot, matrix);
    m4.rotateZ(matrix, time, matrix);
    
    gl.useProgram(programInfo.program);
    // calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
    twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
    // calls gl.uniformXXX
    twgl.setUniforms(programInfo, {
      color: scene.color,
      matrix: matrix,
    });
    // calls gl.drawArrays or gl.drawElements
    twgl.drawBufferInfo(gl, bufferInfo);
  });

  requestAnimationFrame(render);
}

requestAnimationFrame(render);
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>

如果您不是在每一帧都渲染每个视口,则在创建webgl上下文时需要传递preserveDrawingBuffer: true

每帧仅更新一个视口的示例

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl', {
  preserveDrawingBuffer: true,
});

const vs = `
attribute vec4 position;
uniform mat4 matrix;
void main() {
  gl_Position = matrix * position;
}
`;
const fs = `
precision mediump float;
uniform vec4 color;
void main() {
  gl_FragColor = color;
}
`;

const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.primitives.createCylinderBufferInfo(gl, 1, 1, 24, 1);

const scenes = [
  { 
     viewport: [0, 0, 150, 150],
     xRot: 0, 
     zRot: 0, 
     bg: [1, 0, 0, 1], 
     color: [0, 1, 1, 1],
  },
  { 
     viewport: [150, 0, 150, 50],
     xRot: Math.PI * .5, 
     zRot: 0, 
     bg: [0, 1, 0, 1], 
     color: [1, 0, 1, 1],
  },
  { 
     viewport: [150, 50, 150, 100],
     xRot: 0, 
     zRot: Math.PI * 0.25, 
     bg: [0, 0, 1, 1], 
     color: [1, 1, 0, 1],
  },
];

let count = 0;
function render(time) {
  ++count;
  time *= 0.001;
 
  gl.enable(gl.SCISSOR_TEST);

  const ndx = count % scenes.length;
  const scene = scenes[ndx];
  gl.viewport(...scene.viewport);
  gl.scissor(...scene.viewport);

  gl.clearColor(...scene.bg);
  gl.clear(gl.COLOR_BUFFER_BIT);

  const fov = Math.PI * 0.25;
  const aspect = scene.viewport[2] / scene.viewport[3];
  const near = 0.1;
  const far = 10;
  const matrix = m4.perspective(fov, aspect, near, far);
  m4.translate(matrix, [Math.sin(time + ndx), 0, -4], matrix);
  m4.rotateX(matrix, scene.xRot, matrix);
  m4.rotateZ(matrix, scene.zRot, matrix);
  m4.rotateZ(matrix, time, matrix);

  gl.useProgram(programInfo.program);
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  twgl.setUniforms(programInfo, {
    color: scene.color,
    matrix: matrix,
  });
  twgl.drawBufferInfo(gl, bufferInfo);

  requestAnimationFrame(render);
}

requestAnimationFrame(render);
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>