webgl:绘制多个圆圈的最快方法 [英] webgl: fastest approach to drawing many circles

查看:116
本文介绍了webgl:绘制多个圆圈的最快方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在绘制数千个圆,实例化一个圆形几何(许多三角形).

I'm currently drawing thousands of circles, instancing a circle geometry (many triangles).

或者,我可以简单地实例化一个四边形(2个三角形),但是使用距离函数和discard在片段着色器中切出一个圆.

alternatively, I could simply instance a quad (2 triangles), but cut out a circle in the fragment shader, using a distance function and discard.

哪种方法会更快? -绘制许多三角形是否比片段着色器中的计算更昂贵?

which approach would be faster? -- is drawing many triangles more expensive than the calculations done in the fragment shader?

推荐答案

最快的方法可能取决于GPU和许多其他因素,例如您如何绘制圆,2D,3D,是否将它们混合在一起,您是否使用z缓冲区等...,但总的来说,更少的三角形快于更多的三角形,更少的像素快于更多的三角形.所以...,我们真正能做的就是尝试.

The fastest way might depend on the GPU and lots of other factors like how you're drawing the circles, 2D, 3D, are you blending them, are you using the z-buffer, etc... but in general, less triangles is faster than more, and less pixels is faster than more. So...., all we can really do is try.

首先,我们仅需绘制纹理四边形而无需融合.首先,我似乎总是从WebGL中获得不一致的性能,但是在我的GPU上进行的测试中,使用实例化在此300x150的画布中以60fps的速度获得了20k-30k的四边形

First lets just draw textured quads with no blending. First off I always seem to get inconsistent perf from WebGL but in my tests on my GPU I get 20k-30k quads at 60fps in this 300x150 canvas using instancing

function main() {
  const gl = document.querySelector('canvas').getContext('webgl');
  const ext = gl.getExtension('ANGLE_instanced_arrays');
  if (!ext) {
    return alert('need ANGLE_instanced_arrays');
  }
  twgl.addExtensionsToContext(gl);
  
  const vs = `
  attribute float id;
  attribute vec4 position;
  attribute vec2 texcoord;
  
  uniform float time;
  
  varying vec2 v_texcoord;
  varying vec4 v_color;
  
  void main() {
    float o = id + time;
    gl_Position = position + vec4(
        vec2(
             fract(o * 0.1373),
             fract(o * 0.5127)) * 2.0 - 1.0,
        0, 0);
        
    v_texcoord = texcoord;
    v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
  }`;
  
  const fs = `
  precision mediump float;
  varying vec2 v_texcoord;
  varying vec4 v_color;
  uniform sampler2D tex;
  void main() {
    gl_FragColor = texture2D(tex, v_texcoord) * v_color;
  }
  `; 
  
  // compile shaders, link program, look up locations
  const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

  const maxCount = 250000;
  const ids = new Float32Array(maxCount);
  for (let i = 0; i < ids.length; ++i) {
    ids[i] = i;
  }
  const x = 16 / 300 * 2;
  const y = 16 / 150 * 2;
  
  const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
    position: {
      numComponents: 2,
      data: [
       -x, -y,
        x, -y,
       -x,  y,
       -x,  y,
        x, -y,
        x,  y,
    	],
    },
    texcoord: [
        0, 1,
        1, 1,
        0, 0,
        0, 0,
        1, 1,
        1, 0,    
    ],
    id: {
      numComponents: 1,
      data: ids,
      divisor: 1,
    }
  });
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  
  {
    const ctx = document.createElement('canvas').getContext('2d');
    ctx.canvas.width = 32;
    ctx.canvas.height = 32;
    ctx.fillStyle = 'white';
    ctx.beginPath();
    ctx.arc(16, 16, 15, 0, Math.PI * 2);
    ctx.fill();
    const tex = twgl.createTexture(gl, { src: ctx.canvas });
  }
  
  const fpsElem = document.querySelector('#fps');
  const countElem = document.querySelector('#count');
  
  let count;  
  function getCount() {
    count = Math.min(maxCount, parseInt(countElem.value));
  }
  
  countElem.addEventListener('input', getCount);
  getCount();
  
  const maxHistory = 60;
  const fpsHistory = new Array(maxHistory).fill(0);
  let historyNdx = 0;
  let historyTotal = 0;
  
  let then = 0;
  function render(now) {
    const deltaTime = now - then;
    then = now;
    
    historyTotal += deltaTime - fpsHistory[historyNdx];
    fpsHistory[historyNdx] = deltaTime;
    historyNdx = (historyNdx + 1) % maxHistory;
    
    fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
    
    gl.useProgram(programInfo.program);
    twgl.setUniforms(programInfo, {time: now * 0.001});
    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, count);
    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
}
main();

canvas { display: block; border: 1px solid black; }

<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>

我对几何图形重复而不是实例化,在60fps时获得相同的性能.这让我感到惊讶,因为在7-8年以前,当我测试重复的几何图形时,速度提高了20-30%.那是因为现在有了更好的GPU还是更好的驱动程序,还是我不知道.

And I get the same perf at 60fps using repeated to geometry instead of instancing. That's surprising to me because 7-8yrs ago when I tested repeated geometry was 20-30% faster. Whether that's because of having a better GPU now or a better driver or what I have no idea.

function main() {
  const gl = document.querySelector('canvas').getContext('webgl');
  
  const vs = `
  attribute float id;
  attribute vec4 position;
  attribute vec2 texcoord;
  
  uniform float time;
  
  varying vec2 v_texcoord;
  varying vec4 v_color;
  
  void main() {
    float o = id + time;
    gl_Position = position + vec4(
        vec2(
             fract(o * 0.1373),
             fract(o * 0.5127)) * 2.0 - 1.0,
        0, 0);
        
    v_texcoord = texcoord;
    v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
  }`;
  
  const fs = `
  precision mediump float;
  varying vec2 v_texcoord;
  varying vec4 v_color;
  uniform sampler2D tex;
  void main() {
    gl_FragColor = texture2D(tex, v_texcoord) * v_color;
  }
  `; 
  
  // compile shaders, link program, look up locations
  const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

  const maxCount = 250000;
  const x = 16 / 300 * 2;
  const y = 16 / 150 * 2;
  
  const quadPositions = [
     -x, -y,
      x, -y,
     -x,  y,
     -x,  y,
      x, -y,
      x,  y,
  ];
  const quadTexcoords = [
      0, 1,
      1, 1,
      0, 0,
      0, 0,
      1, 1,
      1, 0,    
  ];
  const positions = new Float32Array(maxCount * 2 * 6);
  const texcoords = new Float32Array(maxCount * 2 * 6);
  for (let i = 0; i < maxCount; ++i) {
    const off = i * 2 * 6;
    positions.set(quadPositions, off);
    texcoords.set(quadTexcoords, off);
  }
  const ids = new Float32Array(maxCount * 6);
  for (let i = 0; i < ids.length; ++i) {
    ids[i] = i / 6 | 0;
  }
      
  const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
    position: {
      numComponents: 2,
      data: positions,
    },
    texcoord: texcoords,
    id: {
      numComponents: 1,
      data: ids,
    }
  });
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  
  {
    const ctx = document.createElement('canvas').getContext('2d');
    ctx.canvas.width = 32;
    ctx.canvas.height = 32;
    ctx.fillStyle = 'white';
    ctx.beginPath();
    ctx.arc(16, 16, 15, 0, Math.PI * 2);
    ctx.fill();
    const tex = twgl.createTexture(gl, { src: ctx.canvas });
  }
  
  const fpsElem = document.querySelector('#fps');
  const countElem = document.querySelector('#count');
  
  let count;  
  function getCount() {
    count = Math.min(maxCount, parseInt(countElem.value));
  }
  
  countElem.addEventListener('input', getCount);
  getCount();
  
  const maxHistory = 60;
  const fpsHistory = new Array(maxHistory).fill(0);
  let historyNdx = 0;
  let historyTotal = 0;
  
  let then = 0;
  function render(now) {
    const deltaTime = now - then;
    then = now;
    
    historyTotal += deltaTime - fpsHistory[historyNdx];
    fpsHistory[historyNdx] = deltaTime;
    historyNdx = (historyNdx + 1) % maxHistory;
    
    fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
    
    gl.useProgram(programInfo.program);
    twgl.setUniforms(programInfo, {time: now * 0.001});
    gl.drawArrays(gl.TRIANGLES, 0, 6 * count);
    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
}
main();

canvas { display: block; border: 1px solid black; }

<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>

接下来的事情就是片段着色器中的纹理或计算圆.

Next thing would be textures or computing a circle in the fragment shader.

function main() {
  const gl = document.querySelector('canvas').getContext('webgl');
  const ext = gl.getExtension('ANGLE_instanced_arrays');
  if (!ext) {
    return alert('need ANGLE_instanced_arrays');
  }
  twgl.addExtensionsToContext(gl);
  
  const vs = `
  attribute float id;
  attribute vec4 position;
  attribute vec2 texcoord;
  
  uniform float time;
  
  varying vec2 v_texcoord;
  varying vec4 v_color;
  
  void main() {
    float o = id + time;
    gl_Position = position + vec4(
        vec2(
             fract(o * 0.1373),
             fract(o * 0.5127)) * 2.0 - 1.0,
        0, 0);
        
    v_texcoord = texcoord;
    v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
  }`;
  
  const fs = `
  precision mediump float;
  varying vec2 v_texcoord;
  varying vec4 v_color;
  void main() {
    gl_FragColor = mix(
       v_color, 
       vec4(0), 
       step(1.0, length(v_texcoord.xy * 2. - 1.)));
  }
  `; 
  
  // compile shaders, link program, look up locations
  const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

  const maxCount = 250000;
  const ids = new Float32Array(maxCount);
  for (let i = 0; i < ids.length; ++i) {
    ids[i] = i;
  }
  const x = 16 / 300 * 2;
  const y = 16 / 150 * 2;
  
  const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
    position: {
      numComponents: 2,
      data: [
       -x, -y,
        x, -y,
       -x,  y,
       -x,  y,
        x, -y,
        x,  y,
    	],
    },
    texcoord: [
        0, 1,
        1, 1,
        0, 0,
        0, 0,
        1, 1,
        1, 0,    
    ],
    id: {
      numComponents: 1,
      data: ids,
      divisor: 1,
    }
  });
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  
  const fpsElem = document.querySelector('#fps');
  const countElem = document.querySelector('#count');
  
  let count;  
  function getCount() {
    count = Math.min(maxCount, parseInt(countElem.value));
  }
  
  countElem.addEventListener('input', getCount);
  getCount();
  
  const maxHistory = 60;
  const fpsHistory = new Array(maxHistory).fill(0);
  let historyNdx = 0;
  let historyTotal = 0;
  
  let then = 0;
  function render(now) {
    const deltaTime = now - then;
    then = now;
    
    historyTotal += deltaTime - fpsHistory[historyNdx];
    fpsHistory[historyNdx] = deltaTime;
    historyNdx = (historyNdx + 1) % maxHistory;
    
    fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
    
    gl.useProgram(programInfo.program);
    twgl.setUniforms(programInfo, {time: now * 0.001});
    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, count);
    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
}
main();

canvas { display: block; border: 1px solid black; }

<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>

我没有可测量的差异.尝试您的圈子功能

I get no measureable difference. Trying your circle function

function main() {
  const gl = document.querySelector('canvas').getContext('webgl');
  const ext = gl.getExtension('ANGLE_instanced_arrays');
  if (!ext) {
    return alert('need ANGLE_instanced_arrays');
  }
  twgl.addExtensionsToContext(gl);
  
  const vs = `
  attribute float id;
  attribute vec4 position;
  attribute vec2 texcoord;
  
  uniform float time;
  
  varying vec2 v_texcoord;
  varying vec4 v_color;
  
  void main() {
    float o = id + time;
    gl_Position = position + vec4(
        vec2(
             fract(o * 0.1373),
             fract(o * 0.5127)) * 2.0 - 1.0,
        0, 0);
        
    v_texcoord = texcoord;
    v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
  }`;
  
  const fs = `
  precision mediump float;
  varying vec2 v_texcoord;
  varying vec4 v_color;
  
  float circle(in vec2 st, in float radius) {
    vec2 dist = st - vec2(0.5);
    return 1.0 - smoothstep(
       radius - (radius * 0.01),
       radius +(radius * 0.01),
       dot(dist, dist) * 4.0);
  }
  
  void main() {
    gl_FragColor = mix(
       vec4(0), 
       v_color, 
       circle(v_texcoord, 1.0));
  }
  `; 
  
  // compile shaders, link program, look up locations
  const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

  const maxCount = 250000;
  const ids = new Float32Array(maxCount);
  for (let i = 0; i < ids.length; ++i) {
    ids[i] = i;
  }
  const x = 16 / 300 * 2;
  const y = 16 / 150 * 2;
  
  const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
    position: {
      numComponents: 2,
      data: [
       -x, -y,
        x, -y,
       -x,  y,
       -x,  y,
        x, -y,
        x,  y,
    	],
    },
    texcoord: [
        0, 1,
        1, 1,
        0, 0,
        0, 0,
        1, 1,
        1, 0,    
    ],
    id: {
      numComponents: 1,
      data: ids,
      divisor: 1,
    }
  });
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  
  const fpsElem = document.querySelector('#fps');
  const countElem = document.querySelector('#count');
  
  let count;  
  function getCount() {
    count = Math.min(maxCount, parseInt(countElem.value));
  }
  
  countElem.addEventListener('input', getCount);
  getCount();
  
  const maxHistory = 60;
  const fpsHistory = new Array(maxHistory).fill(0);
  let historyNdx = 0;
  let historyTotal = 0;
  
  let then = 0;
  function render(now) {
    const deltaTime = now - then;
    then = now;
    
    historyTotal += deltaTime - fpsHistory[historyNdx];
    fpsHistory[historyNdx] = deltaTime;
    historyNdx = (historyNdx + 1) % maxHistory;
    
    fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
    
    gl.useProgram(programInfo.program);
    twgl.setUniforms(programInfo, {time: now * 0.001});
    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, count);
    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
}
main();

canvas { display: block; border: 1px solid black; }

<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>

我再也没有可测量的差异.注意:就像我上面说的,我在WebGL中得到的结果非常不一致.当我运行第一个测试时,我以60fps的速度拍摄了28k.当我跑第二个时,我得到了23k.我很惊讶,因为我期望第二个更快,所以我再次跑了第一个,只有23k.最后一个我拿到29k,再次感到惊讶,但是后来我又回去做前一个,拿到了29k.基本上,这意味着在WebGL中测试计时几乎是不可能的.鉴于所有事情都是多过程的,所以有太多的运动部件,以至于无法获得恒定的结果.

I again get no measurable difference. Note: like I said above I get wildly inconsistent results in WebGL. When I ran the first test I got 28k at 60fps. When I ran the second I got 23k. I was surprised since I expected the 2nd to be faster so I ran the first again and only got 23k. The last one I got 29k and was again surprise but then I went back and did the previous and got 29k. Basically that means testing timing in WebGL is nearly impossible. There are so many moving parts given everything is multi-process that getting constant results seems impossible.

可以尝试丢弃

function main() {
  const gl = document.querySelector('canvas').getContext('webgl');
  const ext = gl.getExtension('ANGLE_instanced_arrays');
  if (!ext) {
    return alert('need ANGLE_instanced_arrays');
  }
  twgl.addExtensionsToContext(gl);
  
  const vs = `
  attribute float id;
  attribute vec4 position;
  attribute vec2 texcoord;
  
  uniform float time;
  
  varying vec2 v_texcoord;
  varying vec4 v_color;
  
  void main() {
    float o = id + time;
    gl_Position = position + vec4(
        vec2(
             fract(o * 0.1373),
             fract(o * 0.5127)) * 2.0 - 1.0,
        0, 0);
        
    v_texcoord = texcoord;
    v_color = vec4(fract(vec3(id) * vec3(0.127, 0.373, 0.513)), 1);
  }`;
  
  const fs = `
  precision mediump float;
  varying vec2 v_texcoord;
  varying vec4 v_color;
  
  float circle(in vec2 st, in float radius) {
    vec2 dist = st - vec2(0.5);
    return 1.0 - smoothstep(
       radius - (radius * 0.01),
       radius +(radius * 0.01),
       dot(dist, dist) * 4.0);
  }
  
  void main() {
    if (circle(v_texcoord, 1.0) < 0.5) {
      discard;
    }
    gl_FragColor = v_color;
  }
  `; 
  
  // compile shaders, link program, look up locations
  const programInfo = twgl.createProgramInfo(gl, [vs, fs]);

  const maxCount = 250000;
  const ids = new Float32Array(maxCount);
  for (let i = 0; i < ids.length; ++i) {
    ids[i] = i;
  }
  const x = 16 / 300 * 2;
  const y = 16 / 150 * 2;
  
  const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
    position: {
      numComponents: 2,
      data: [
       -x, -y,
        x, -y,
       -x,  y,
       -x,  y,
        x, -y,
        x,  y,
    	],
    },
    texcoord: [
        0, 1,
        1, 1,
        0, 0,
        0, 0,
        1, 1,
        1, 0,    
    ],
    id: {
      numComponents: 1,
      data: ids,
      divisor: 1,
    }
  });
  twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
  
  const fpsElem = document.querySelector('#fps');
  const countElem = document.querySelector('#count');
  
  let count;  
  function getCount() {
    count = Math.min(maxCount, parseInt(countElem.value));
  }
  
  countElem.addEventListener('input', getCount);
  getCount();
  
  const maxHistory = 60;
  const fpsHistory = new Array(maxHistory).fill(0);
  let historyNdx = 0;
  let historyTotal = 0;
  
  let then = 0;
  function render(now) {
    const deltaTime = now - then;
    then = now;
    
    historyTotal += deltaTime - fpsHistory[historyNdx];
    fpsHistory[historyNdx] = deltaTime;
    historyNdx = (historyNdx + 1) % maxHistory;
    
    fpsElem.textContent = (1000 / (historyTotal / maxHistory)).toFixed(1);
    
    gl.useProgram(programInfo.program);
    twgl.setUniforms(programInfo, {time: now * 0.001});
    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 6, count);
    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
}
main();

canvas { display: block; border: 1px solid black; }

<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
<div>fps: <span id="fps"></span></div>
<div>count: <input type="number" id="count" min="0" max="1000000" value="25000"></div>

鉴于时间不确定,我不确定,但我的印象是丢弃速度较慢. IIRC丢弃很慢,因为如果不丢弃,GPU甚至会在执行片段着色器之前就知道它会更新z缓冲区,就像丢弃一样,直到着色器执行后它才知道,并且这种差异意味着某些事情无法执行也要进行优化.

Given the inconsistent timing I can't be sure but my impression is discard is slower. IIRC discard is slow because without discard the GPU knows even before it executes the fragment shader that it's going to update the z-buffer where as with discard it doesn't know until after the shader executes and that that difference means certain things can't be optimized as well.

我要在这里停下来,因为要尝试的东西太多了.

I'm going to stop there because there's just too many combinations of things to try.

我们可以尝试混合.混合通常也较慢,因为它必须混合(读取背景),但是比丢弃慢吗?我不知道.

We could try blending on. Blending is also generally slower though since it has to blend (read the background) but is it slower than discard? I don't know.

您要进行深度测试吗?如果是这样,那么绘制顺序就很重要.

Do you have the depth test on? If so then draw order will be important.

要测试的另一件事是使用非四边形(例如六边形或八边形),因为这样会使通过片段着色器的像素减少.我怀疑您可能需要使圆圈变大才能看到,但是如果我们有一个100x100像素的四倍即10k像素.如果我们有完美的圆几何,大约是pi * r ^ 2或〜7853或少了21%的像素.六边形大约为8740像素或少11%.介于两者之间的八角形.少绘制11%到21%的像素通常是一种制胜法宝,但是对于六边形,当然当然要多绘制3倍的三角形,对于八角形要多绘制4倍.您基本上必须测试所有这些情况.

Yet another thing to test is using non-quads like hexgons or octogons as that would run less pixels through the fragment shader. I suspect you might need to make the circles bigger to see that but if we have a 100x100 pixel quad that's 10k pixels. If we have perfect circle geometry that's about pi*r^2 or ~7853 or 21% less pixels. A Hexagon would be ~8740 pixels or 11% less. An octogon somewhere in between. Drawing 11% to 21% less pixels is usually a win but of course course for hexagon you'd be drawing 3x more triangles, for an octogon 4x more. You'd basically have to test all these cases.

这指出了另一个问题,我相信您会在较大的画布上使用较大的圆圈获得相对的相对结果,因为每个圆圈会有更多的像素,因此,对于任何给定数量的圆圈,将花费更多的时间百分比绘制像素,减少计算顶点和/或减少时间,重新启动GPU绘制下一个圆.

That points out another issue in that I believe you'd get different relative results with larger circles on a larger canvas since there'd be more pixels per circle so for any given number of circles drawn more % of time would be spent drawing pixels and less calculating vertices and/or less time restarting the GPU to draw the next circle.

在Chrome和Firefox上进行测试在所有情况下,我在同一台计算机上使用Chrome都能获得60k-66k的收益.鉴于WebGL本身几乎无能为力,所以不知道为什么差异如此之大.所有4个测试每帧只有一个绘图调用.但是无论如何,对于这种情况,至少到2019-10年,Chrome浏览器的速度是Firefox的两倍以上

Testing on Chrome vs Firefox I got 60k-66k in all cases in Chrome on the same machine. No idea why the difference is so vast given that WebGL itself is doing almost nothing. All 4 tests only have a single draw call per frame. But whatever, at least as of 2019-10 Chrome as more than twice as fast for this particular case than Firefox

一个想法是我有一台双GPU笔记本电脑.创建上下文时,您可以像在

One idea is I have a dual GPU laptop. When you create the context you can tell WebGL what you're targeting by passing in the powerPreference context creation attribute as in in

const gl = document.createContext('webgl', {
  powerPreference: 'high-performance',
});

选项为默认",低功耗",高性能". 默认"的意思是让浏览器决定",但最终所有这些都意味着让浏览器决定".无论如何,上面的设置对我来说并不会改变Firefox中的任何内容.

The options are 'default', 'low-power', 'high-performance'. 'default' means "let the browser decide" but ultimately all of them mean "let the browser decide". In any case setting that above didn't change anything in firefox for me.

这篇关于webgl:绘制多个圆圈的最快方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆