如果两者都使用硬件加速(GPU)来执行代码,为什么WebGL比Canvas更快?
我的意思是,我想知道从代码到处理器的低级链路为什么会出现这种情况。
发生了什么?Canvas/WebGL直接与驱动程序通信,然后与视频卡通信吗?
如果两者都使用硬件加速(GPU)来执行代码,为什么WebGL比Canvas更快?
我的意思是,我想知道从代码到处理器的低级链路为什么会出现这种情况。
发生了什么?Canvas/WebGL直接与驱动程序通信,然后与视频卡通信吗?
arc
绘制一个实心圆。ctx.beginPath():
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.fill();
但请等一下...根据我们对 GL 工作原理的了解,如果我们调用
beginPath
创建一个缓冲区 (gl.bufferData
)arc
生成三角形点以绘制圆,并使用gl.bufferData
上传。fill
调用gl.drawArrays
或gl.drawElements
stroke
而不是 fill
,则在第2步时canvas无法生成这些点,因为我们需要针对实心圆 (fill) 和空心圆 (stroke) 的不同点集。所以,真正发生的事情更像是:
如果我们要绘制两个圆,那么同样的步骤可能会重复。
beginPath
创建或重置某些内部缓冲区arc
将生成构成圆的点放入内部缓冲区fill
获取该内部缓冲区中的点,为该内部缓冲区中的点生成正确的三角形集合到一个 GL 缓冲区中,然后使用gl.bufferData
上传它们,最后调用gl.drawArrays
或gl.drawElements
gl.drawArrays
或gl.drawElements
来绘制我们的圆。如果我们想要绘制第二个圆?我们只需更新一个uniform并再次调用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>
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
,它可能生成的点比用半径2000调用要少。画布可能会缓存这些点,但考虑到命中率很小,这似乎不太可能。arc
10000次,而且不管怎样,它每帧都必须为10000个圆生成点,而不仅仅是在开始时生成一次,并且必须调用gl.drawXXX
10000次,而不仅仅是一次。
<canvas>
元素工作,所以我不知道你想将其与什么进行比较... - jplatte