WebGL - 使用网格作为倒置遮罩

WebGL - Use a mesh as inverted mask

我需要将我的 canvas 完全涂成黑色,旋转立方体除外,它必须保持透明以显示位于 canvas 下方的页面内容。 canvas 应该作为页面内容的掩码。

我认为我的问题可以减少到 。 stancil 解决方案将立方体转换为蒙版,我需要的是倒置蒙版。

有没有办法打印立方体外面的所有东西,让立方体区域完全透明?

提前致谢。

正如@pleup 所说,只需清除不透明颜色,然后使用透明颜色绘制

webgl

var geoVS = `
attribute vec4 position;
uniform mat4 matrix;

void main() {
  gl_Position = matrix * position;
}
`;
var geoFS = `
precision mediump float;
void main() {
  gl_FragColor = vec4(0); 
}
`;

const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl", {
  powerPreference: 'low-power',
});
const prgInfo = twgl.createProgramInfo(gl, [geoVS, geoFS]);

const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);

function render(time) {
  time *= 0.001;
  
  twgl.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clearColor(0, 0, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
  
  var fov = Math.PI * .25;
  var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  var zNear = 0.1;
  var zFar = 10;
  var mat = m4.perspective(fov, aspect, zNear, zFar);
  mat = m4.translate(mat, [0, 0, -2]);
  mat = m4.rotateX(mat, time * 0.81);
  mat = m4.rotateZ(mat, time * 0.77);
  
  // draw geometry to generate stencil
  gl.useProgram(prgInfo.program);
  
  twgl.setBuffersAndAttributes(gl, prgInfo, bufferInfo);
  twgl.setUniforms(prgInfo, {
    matrix: mat,
  });

  gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0);
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
html, body { 
  margin: 0;
  height: 100%;
  font-size: xx-large;
}
canvas { 
  position: fixed;
  left: 0;
  top: 0;
  width: 100vw; 
  height: 100vh; 
  display: block;
  pointer-events: none;
}
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>


<div>
content goes here

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed consequat nec tellus non suscipit. Proin fermentum ante ut justo pharetra placerat. Nullam imperdiet eros lectus, non scelerisque lectus gravida sit amet. Duis in justo consectetur,  tincidunt mauris vel, tempus augue. Phasellus venenatis, dui in euismod aliquet, ante lorem efficitur arcu, sed lacinia turpis dui eu metus. Cras ut bibendum velit. Integer lobortis lacus porta odio faucibus, non venenatis arcu pharetra. Praesent fringilla nulla sit amet lectus tempus, id lobortis ligula suscipit. ❤️ Donec sapien erat, sagittis a sem non, vulputate molestie lectus. Etiam id maximus tortor. Pellentesque egestas, ligula sed blandit tristique, est sem facilisis elit, accumsan pellentesque est arcu ac nisl. Sed laoreet nisi sit amet scelerisque convallis.

</div>

<canvas></canvas>

不是立方体,只是为了清楚起见,您应该使用 canvas 2D

轻松做到这一点

const m4 = twgl.m4;
const ctx = document.querySelector("canvas").getContext("2d", {
  powerPreference: 'low-power',
});

function render(time) {
  time *= 0.001;
  
  twgl.resizeCanvasToDisplaySize(ctx.canvas);
  
  ctx.globalCompositeOperation = "source-over";
  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.save();
  {
    ctx.globalCompositeOperation = "destination-out";
    ctx.fillStyle = "rgba(0,0,0,1)";
    ctx.translate(ctx.canvas.width / 2, ctx.canvas.height / 2);
    ctx.rotate(time);
    ctx.fillRect(ctx.canvas.width / -4,
                 ctx.canvas.height / -4,
                 ctx.canvas.width / 2,
                 ctx.canvas.height / 2);
  }
  ctx.restore();
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
html, body { 
  margin: 0;
  height: 100%;
  font-size: xx-large;
}
canvas { 
  position: fixed;
  left: 0;
  top: 0;
  width: 100vw; 
  height: 100vh; 
  display: block;
  pointer-events: none;
}
<script src="https://twgljs.org/dist/3.x/twgl.min.js"></script>


<div>
content goes here

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed consequat nec tellus non suscipit. Proin fermentum ante ut justo pharetra placerat. Nullam imperdiet eros lectus, non scelerisque lectus gravida sit amet. Duis in justo consectetur,  tincidunt mauris vel, tempus augue. Phasellus venenatis, dui in euismod aliquet, ante lorem efficitur arcu, sed lacinia turpis dui eu metus. Cras ut bibendum velit. Integer lobortis lacus porta odio faucibus, non venenatis arcu pharetra. Praesent fringilla nulla sit amet lectus tempus, id lobortis ligula suscipit. ❤️ Donec sapien erat, sagittis a sem non, vulputate molestie lectus. Etiam id maximus tortor. Pellentesque egestas, ligula sed blandit tristique, est sem facilisis elit, accumsan pellentesque est arcu ac nisl. Sed laoreet nisi sit amet scelerisque convallis.

</div>

<canvas></canvas>