webgl中的旋转曲线

Rotate curve in webgl

我用线段近似曲线:

for (i=1; i<=100; i=i+0.2)
    {
        arr = calculateCurve(i, 1, 1, 1, 1); //function returns an array of verticles
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
            prevArr[0]/scale,
            prevArr[1]/scale,
            prevArr[2]/scale,
            arr[0]/scale,
            arr[1]/scale,
            arr[2]/scale
        ]), gl.STATIC_DRAW);
        gl.drawArrays(gl.LINES, 0, 2);

        prevArr = arr;

    }

我需要在不使用 gl.drawArrays() 的情况下旋转曲线,因为在这种情况下性能非常慢。 我会创建一个包含 100 个顶点的巨大缓冲区,但我想知道是否有一种方法可以通过更改顶点着色器中的旋转矩阵来重绘场景。

不太清楚旋转曲线是什么意思。我看到至少有两种解释。一种是您希望曲线顶点位于同一位置但改变查看器位置,以便您可以从不同角度查看同一条曲线。第二个是你想要每一帧都有不同的曲线形状。

如果你想要的是 1),那么你所要做的就是将一个统一的矩阵发送到 GPU,然后在顶点着色器中执行 gl_Position = matrix * position。这样做意味着您不必每帧都重新生成曲线上的顶点位置。

如果你想要的是2),那么你需要想出一些数学来计算顶点着色器中曲线上每个点的位置。如何做到这一点取决于具体情况,我认为您需要展示更多关于如何计算曲线位置的代码。

创建 "huge" 缓冲区在这里不是问题,缓冲区的大小甚至达不到 10kb(如果您使用不同于 LINE -> LINE_LOOPLINE_STRIP ),但是多次调用 glDrawArrays 是。

这里正确的方法是缓冲孔线。为此生成一个 Float32Array ,其大小可以容纳所有要渲染的浮点数。然后恰好调用 glBufferDataglDrawArrays 一次。

如果您不每帧都更改线条,您也可以在第一次缓冲线条后跳过 glBufferData

您可以通过将顶点乘以旋转矩阵来旋转 WebGL 中的顶点。

例如,此代码将生成一个在 Z 轴上旋转顶点的矩阵。

function rotationZ(angleInRadians) {

  var c = Math.cos(angleInRadians);
  var s = Math.sin(angleInRadians);

  return [
    c, s, 0, 0,
   -s, c, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1,
  ];
}

这是一个工作示例:

function rotationZ(angleInRadians) {

  var c = Math.cos(angleInRadians);
  var s = Math.sin(angleInRadians);

  return [
    c, s, 0, 0,
    -s, c, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1,
  ];
}
    
// Using TWGL (twgljs.org) to keep the code small

  var gl = document.getElementById("c").getContext("webgl");
  // compiles shader, links and looks up locations
  var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);

  // make some curve points
  points = [];
  for (var i = 0; i < 100; ++i) {
    var a = i / 100 * Math.PI * 2;
    var r = 0.5;
    points.push(
      Math.sin(Math.sin(a * 2.)) * r , 
      Math.cos(a) * r);
  }

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

  function render(time) {
    var uniforms = {
      u_matrix: rotationZ(time * 0.001),
    };

    gl.useProgram(programInfo.program);
    // calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
    twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
    // calls gl.uniformXXX, gl.activeTexture, gl.bindTexture
    twgl.setUniforms(programInfo, uniforms);
    // calls gl.drawArray or gl.drawElements
    twgl.drawBufferInfo(gl, bufferInfo, gl.LINE_LOOP);

    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
canvas { border: 1px solid blue; }
<!-- 

note! I'm using a square canvas so I don't have to deal with aspect 
which would complicate the example

See the articles linked in the answer for details about aspect

-->
<canvas id="c" width="150" height="150"></canvas>
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<script id="vs" type="notjs">
attribute vec4 position;
uniform mat4 u_matrix;

void main() {
  gl_Position = u_matrix * position;
}
</script>
<script id="fs" type="notjs">
precision mediump float;

void main() {
  gl_FragColor = vec4(0,0,0,1);
}
</script>

This article explains how rotation works 其后的文章将过渡到使用矩阵。