gpt4 book ai didi

html - 为什么 WebGL 比 Canvas 快?

转载 作者:行者123 更新时间:2023-12-04 18:05:41 24 4
gpt4 key购买 nike

如果两者都使用硬件加速 (GPU) 来执行代码,为什么 WebGL 比 Canvas 更快?

我的意思是,我想知道为什么在低级别,从代码到处理器的链。

发生什么了? Canvas/WebGL 直接与驱动程序通信,然后与显卡通信?

最佳答案

Canvas 较慢,因为它是通用的,因此很难优化到可以优化 WebGL 的水平。举个简单的例子,用 arc 画一个实心圆.

Canvas 实际上运行在 GPU 之上,并且使用与 WebGL 相同的 API。那么,画圆的时候canvas有什么作用呢?使用 canvas 2d 在 JavaScript 中绘制圆的最少代码是

ctx.beginPath():
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.fill();

您可以在内部想象最简单的实现是

  1. beginPath creates a buffer (gl.bufferData)
  2. arc generates the points for triangles that make a circle and uploads with gl.bufferData.
  3. fill calls gl.drawArrays or gl.drawElements


但是等一下......知道我们对 GL 如何工作 canvas 的了解无法在第 2 步生成点,因为如果我们调用 stroke而不是 fill然后根据我们对 GL 工作原理的了解,我们需要一组不同的点来表示实心圆(填充)和圆的轮廓(笔划)。所以,真正发生的事情更像是

  1. beginPath creates or resets some internal buffer
  2. arc generates the points that make a circle into the internal buffer
  3. fill takes the points in that internal buffer, generates the correct set of triangles for the points in that internal buffer into a GL buffer, uploads them with gl.bufferData, calls gl.drawArrays or gl.drawElements


如果我们想画 2 个圆会发生什么?可能会重复相同的步骤。

让我们将其与我们在 WebGL 中所做的比较。当然,在 WebGL 中,我们必须编写自己的着色器( Canvas has its shaders as well)。我们还必须创建一个缓冲区并用三角形填充一个圆圈,(注意我们已经节省了时间,因为我们跳过了点的中间缓冲区)。然后我们可以调用 gl.drawArraysgl.drawElements画出我们的圆圈。如果我们想画第二个圆圈?我们只需更新制服并调用 gl.drawArrays再次跳过所有其他步骤。

const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
uniform mat4 u_matrix;

void main() {
gl_Position = u_matrix * position;
}
`;

const fs = `
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
`;

const program = twgl.createProgram(gl, [vs, fs]);
const positionLoc = gl.getAttribLocation(program, 'position');
const colorLoc = gl.getUniformLocation(program, 'u_color');
const matrixLoc = gl.getUniformLocation(program, 'u_matrix');

const positions = [];
const radius = 50;
const numEdgePoints = 64;
for (let i = 0; i < numEdgePoints; ++i) {
const angle0 = (i ) * Math.PI * 2 / numEdgePoints;
const angle1 = (i + 1) * Math.PI * 2 / numEdgePoints;
// make a triangle
positions.push(
0, 0,
Math.cos(angle0) * radius,
Math.sin(angle0) * radius,
Math.cos(angle1) * radius,
Math.sin(angle1) * radius,
);
}

const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);

gl.useProgram(program);

const projection = m4.ortho(0, gl.canvas.width, 0, gl.canvas.height, -1, 1);

function drawCircle(x, y, color) {
const mat = m4.translate(projection, [x, y, 0]);
gl.uniform4fv(colorLoc, color);
gl.uniformMatrix4fv(matrixLoc, false, mat);

gl.drawArrays(gl.TRIANGLES, 0, numEdgePoints * 3);
}

drawCircle( 50, 75, [1, 0, 0, 1]);
drawCircle(150, 75, [0, 1, 0, 1]);
drawCircle(250, 75, [0, 0, 1, 1]);
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>


一些开发人员可能会认为 Canvas 缓存了缓冲区,因此它可以重用第二次绘制调用中的点。这可能是真的,但我有点怀疑。为什么?由于 canvas api 的通用性。 fill ,完成所有实际工作的函数不知道点的内部缓冲区中有什么。您可以调用 arc ,然后 moveTo , lineTo ,然后 arc再次,然后调用 fill .当我们到达 fill 时,所有这些点都将在点的内部缓冲区中。 .

const ctx = document.querySelector('canvas').getContext('2d');
ctx.beginPath();
ctx.moveTo(50, 30);
ctx.lineTo(100, 150);
ctx.arc(150, 75, 30, 0, Math.PI * 2);
ctx.fill();
<canvas></canvas>


换句话说,填充需要始终查看所有点。另一件事,我怀疑 arc 试图优化大小。如果您调用 arc半径为 2 时,它产生的点可能比半径为 2000 时产生的点少。 Canvas 可能会缓存这些点,但考虑到命中率可能很小,这似乎不太可能。

无论如何,关键是 WebGL 让您在较低级别进行控制,允许您跳过 Canvas 无法跳过的步骤。它还允许您重用 Canvas 无法重用的数据。

事实上,如果我们知道我们想要绘制 10000 个动画圆圈,我们甚至在 WebGL 中还有其他选项。我们可以为 10000 个圆圈生成点,这是一个有效的选项。我们也可以使用实例化。这两种技术都比 Canvas 快得多,因为在 Canvas 中我们必须调用 arc 10000 次,以一种或另一种方式,它必须每帧生成 10000 个圆圈的点,而不是在开始时只生成一次,它必须调用 gl.drawXXX 10000 次而不是一次。

当然反过来是canvas很容易。绘制圆圈需要 3 行代码。在 WebGL 中,因为您需要设置和编写着色器,它可能需要至少 60 行代码。事实上,上面的例子大约有 60 行,不包括编译和链接着色器的代码(约 10 行)。在该 Canvas 之上支持变换、图案、渐变、蒙版等。我们必须在 WebGL 中添加更多代码行来添加所有选项。所以 Canvas 基本上是用易用性来换取 WebGL 的速度。

关于html - 为什么 WebGL 比 Canvas 快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28867297/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com