webgl 库中的清除圆圈

Clear circle in webgl library

您好,我正在为我的网站使用 javascript 库。库使用 webgl 生成动画。所以它在元素内部创建了一个 canvas 并显示了动画。但我希望该动画看起来像一个甜甜圈。我已经在 canvas 元素上设置了 border-radius 50% 并且它生成了一个圆,但是我需要在 canvas 内切另一个透明圆。这是我想要实现的目标的图像。

我已经尝试操作 html 个元素,但到目前为止没有成功。此外,由于 canvas 后面的背景图像,我无法使用重叠元素。

接下来我尝试的是覆盖库函数,但我从来没有在 webgl 中做过任何事情,所以它很糟糕。我添加了另一种在动画更新后应用的方法。我在 canvas 内切了一个正方形,但没有成功切圆。有没有简单的方法,如何在 webgl 中切割一个圆,我可以放入我的 drawEmptyCircle 方法中,而无需在库中进行任何复杂的编辑?

    drawEmptyCircle: function(){
         gl.enable(gl.SCISSOR_TEST);
         gl.scissor(150, 150, 200, 200);
         gl.clearColor(0, 0, 0, 0);
         gl.clear(gl.COLOR_BUFFER_BIT);
         gl.disable(gl.SCISSOR_TEST);
     },

这里是fiddle

你说你从来没有做过任何WebGL。这表明您需要 some tutorials,因为如何使用 WebGL 无法在堆栈溢出的单个答案中解释。

在 WebGL 中绘制带孔圆的最常见方法是生成三角形,形成带孔圆。这就是所有主要的 GPU 加速 2D 图形库所做的。

function makeCircleTriangles(innerRadius, outerRadius, divisions, start = 0, end = Math.PI * 2) {
  const positions = [];
  for (let d = 0; d <= divisions; ++d) {
    const u = d / divisions;
    const angle = start + (end - start) * u;
    const s = Math.sin(angle);
    const c = Math.cos(angle);
    positions.push(c * innerRadius, s * innerRadius);
    positions.push(c * outerRadius, s * outerRadius);
  }
  const indices = [];
  for (let d = 0; d < divisions; ++d) {
    const offset = d * 2;
    indices.push(offset + 0, offset + 1, offset + 2);
    indices.push(offset + 2, offset + 1, offset + 3);
  }
  return {position, indices};
}

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

const vs = `
attribute vec4 position;
uniform mat4 matrix;
void main() {
  gl_Position = matrix * position;
}
`;

const fs = `
precision highp float;
void main() {
  gl_FragColor = vec4(0, .6, 0, 1);
}
`;

// compile shaders, link progrma, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

const {positions, indices} = makeCircleTriangles(30, 70, 64);

// calls gl.createBuffer, gl.bindBuffer, gl.bufferData for each array
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
  position: { numComponents: 2, data: positions },
  indices,
});

gl.useProgram(programInfo.program);

// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);

// calls gl.uniform
twgl.setUniforms(programInfo, {
  matrix: [
    2 / gl.canvas.clientWidth, 0, 0, 0,
    0, 2 / gl.canvas.clientHeight, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1,
  ],
});

gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);

function makeCircleTriangles(innerRadius, outerRadius, divisions, start = 0, end = Math.PI * 2) {
  const positions = [];
  for (let d = 0; d <= divisions; ++d) {
    const u = d / divisions;
    const angle = start + (end - start) * u;
    const s = Math.sin(angle);
    const c = Math.cos(angle);
    positions.push(c * innerRadius, s * innerRadius);
    positions.push(c * outerRadius, s * outerRadius);
  }
  const indices = [];
  for (let d = 0; d < divisions; ++d) {
    const offset = d * 2;
    indices.push(offset + 0, offset + 1, offset + 2);
    indices.push(offset + 2, offset + 1, offset + 3);
  }
  return {positions, indices};
}
<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>

第二种最常见的方法是绘制一个四边形(2 个三角形),其纹理为带孔的圆形。

我认为你不能在 Canvas 元素上打洞。

Also i cant use overlaping element due to background image behind canvas.

如果你能控制所有元素的绝对位置,这就不是问题了。

例如,我更改了您的初始 jsfiddle。

首先是 HTML 标记。 outer class 用于控制内部元素的绝对位置。 ontop class 在 canvas 上方创建一个圆圈以模仿透明度。

<div class="outer bg">
  <div class="circle"></div>
  <div class="ontop bg"></div>
</div>

在此 CSS 中,所有数字都是相对于您在示例中使用的原始 canvas 大小 (500px x 500px)。我为 canvas (20px) 使用了一些边距,只是为了表明可能有一些更高级的位置。

.bg {
  background-image: url(-your-image-here-);
}
.ontop {
  background-position: -145px -145px;
  position: absolute;
  left: 145px;
  top: 145px;
  width: 250px;
  height: 250px;
  background-color: white;
  border-radius:50%;
}
.outer {
  position:relative;
  background-position: 0 0;
  width: 540px;
  height: 540px;
  padding: 20px;
}

这是有效的 jsfiddle:click.

为了使所有其他元素(文本)可见,我必须使用一个技巧将其 HTML 元素加倍。这是文本示例,它位于背景级别(因此低于 canvas):click.