WebGL: подсчитать количество визуализированных вершин - PullRequest
0 голосов
/ 29 апреля 2018

Используя API WebGL, есть ли способ подсчитать количество вершин, отображаемых в данном холсте? Я видел некоторые инструменты, которые пытаются выполнить эту задачу, но некоторые дают странные результаты (например, Three.js 'renderer.info.render сообщает, что моя сцена имеет 10 134,3 треугольника).

Будем весьма благодарны за любую помощь в использовании необработанного API WebGL для подсчета количества отображаемых вершин (и, в идеале, точек и линий).

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

WebGL не может сделать это за вас, но вы можете добавить свое собственное дополнение.

Самый очевидный способ - просто отслеживать свое использование. Вместо того, чтобы звонить gl.drawXXX, звоните functionThatTracksDrawingCountsXXX и отслеживайте значения самостоятельно.

Вы также можете дополнить контекст WebGL. Пример

// copy this part into a file like `augmented-webgl.js`
// and include it in your page

(function() {
  // NOTE: since WebGL constants are um, constant
  // we could statically init this.
  let primMap;

  function addCount(ctx, type, count) {
    const ctxInfo = ctx.info;
    const primInfo = primMap[type];
    ctxInfo.vertCount += count;
    ctxInfo.primCount[primInfo.ndx] += primInfo.fn(count);
  } 
 
  WebGLRenderingContext.prototype.drawArrays = (function(oldFn) {
    return function(type, offset, count) {
      addCount(this, type, count);
      oldFn.call(this, type, offset, count);
    };
  }(WebGLRenderingContext.prototype.drawArrays));
  
  WebGLRenderingContext.prototype.drawElements = (function(oldFn) {
    return function(type, count, indexType, offset) {
      addCount(this, type, count);
      oldFn.call(this, type, count, indexType, offset);
    };
  }(WebGLRenderingContext.prototype.drawElements));
  
  HTMLCanvasElement.prototype.getContext = (function(oldFn) {
    return function(type, ...args) {
      const ctx = oldFn.call(this, type, args);
      if (ctx && type === "webgl") {
        if (!primMap) {
          primMap = {};
          primMap[ctx.POINTS] = { ndx: 0, fn: count => count, };
          primMap[ctx.LINE_LOOP] = { ndx: 1, fn: count => count, };
          primMap[ctx.LINE_STRIP]= { ndx: 1, fn: count => count - 1, };
          primMap[ctx.LINES] = { ndx: 1, fn: count => count / 2 | 0, };
          primMap[ctx.TRIANGLE_STRIP] = { ndx: 2, fn: count => count - 2, };
          primMap[ctx.TRIANGLE_FAN] = { ndx: 2, fn: count => count - 2, };
          primMap[ctx.TRIANGLES] = { ndx: 2, fn: count => count / 3 | 0, }; 
        };
        ctx.info = {
          vertCount: 0,
          primCount: [0, 0, 0],
        };
      }
      return ctx;
    }
  }(HTMLCanvasElement.prototype.getContext));
}());

// ---- cut above ----

const $ = document.querySelector.bind(document);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({canvas: $('canvas')});

const geometry = new THREE.BoxGeometry(1, 1, 1);
const items = [];
for (let i = 0; i < 50; ++i) {
  let item;
  switch(rand(0, 3) | 0) {
    case 0:
    case 1:
     const material = new THREE.MeshBasicMaterial({
        color: rand(0xFFFFFF) | 0,
        wireframe: rand(0, 3) > 2,
      });
      item = new THREE.Mesh(geometry, material);
      break;
    case 2:
      const pmat = new THREE.PointsMaterial({
        color: rand(0xFFFFFF) | 0,
      });
      item = new THREE.Points(geometry, pmat);
      break;
    default:
      throw "oops";
  }
  item.position.x = rand(-10, 10);
  item.position.y = rand(-10, 10);
  item.position.z = rand(  0, -50);
  scene.add(item);
  items.push(item);
}

camera.position.z = 5;

const countElem = $('#count');

function render(time) {
  time *= 0.001;
  
  resize();

  // animate the items
  items.forEach((items, ndx) => {
    items.rotation.x = time * 1.2 + ndx * 0.01;
    items.rotation.y = time * 1.1;
  });
  
  // turn on/off a random items
  items[rand(items.length) | 0].visible = Math.random() > .5;

  renderer.render(scene, camera);
  
  // get the current counts
  const info = renderer.context.info;
  countElem.textContent = `    VERTS: ${info.vertCount}
   POINTS: ${info.primCount[0]}
    LINES: ${info.primCount[1]}
TRIANGLES: ${info.primCount[2]}`;
  
  // zero out the count
  renderer.context.info.vertCount = 0;
  renderer.context.info.primCount = [0, 0, 0];
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);

function rand(min, max) {
  if (max === undefined) {
    max = min;
    min = 0;
  }
  return Math.random() * (max - min) + min;
}

function resize() {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width || canvas.height !== height) {
    renderer.setSize(width, height, false);
    camera.aspectRatio = width / height;
    camera.updateProjectionMatrix();
  }
}
body { border: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
#ui { position: absolute; left: 1em; top: 1em; background: rgba(0,0,0,.5); color: white; padding: .5em; width: 10em; }


  

Конечно, вы можете добавить поддержку drawArraysInstanced и т. Д. И поддержку WebGL2.

0 голосов
/ 29 апреля 2018

Мы удалили количество обработанных вершин из renderer.info.render, поскольку важным измерением является количество или отображаемые примитивы (например, треугольники, точки, линии). Пожалуйста, прочитайте https://github.com/mrdoob/three.js/pull/13404 и соответствующие вопросы / PR для получения дополнительной информации. Если вы все еще хотите узнать, сколько вершин было обработано, вам нужно посчитать вручную. WebGL не может сделать это для вас.

...