【问题标题】:Clear circle in webgl librarywebgl库中的清除圆圈
【发布时间】:2020-10-08 21:17:54
【问题描述】:

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

我已经尝试过操作 html 元素,但到目前为止还没有成功。由于画布后面的背景图像,我也不能使用重叠元素。

接下来我尝试的是覆盖库函数,但我从未在 webgl 中做过任何事情,所以它很糟糕。我添加了另一种在动画更新后应用的方法。我在画布内切了一个正方形,但圆形没有成功。有没有简单的方法,如何在 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

【问题讨论】:

  • 没有图书馆,很难帮你。您能否链接到您正在使用的库,或者更好的是,将您的代码放在 stack-sn-p 中以便我们可以对其进行实时测试?
  • 确定这是一个库sirxemic.github.io/jquery.ripples,我会做一个小提琴演示
  • 演示正在运行。

标签: javascript html5-canvas webgl


【解决方案1】:

您说您从未做过任何 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 个三角形),其纹理为圆形,其中有一个孔。

【讨论】:

    【解决方案2】:

    我认为你不能在 Canvas 元素中打孔。

    由于画布后面的背景图像,我也不能使用重叠元素。

    如果你可以控制所有元素的绝对位置,这将不是问题。

    作为一个例子,我改变了你最初的 jsfiddle。

    首先是 HTML 标记。 outer 类用于控制内部元素的绝对位置。 ontop 类在画布上方创建一个圆圈来模拟透明度。

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

    在此 CSS 中,所有数字都与您在示例中使用的原始画布大小(500 像素 x 500 像素)相关。我在画布上使用了一些边距(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 元素加倍。这是带有文本的示例,它位于背景级别(位于画布下方):click

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      相关资源
      最近更新 更多