WebGL:计算渲染顶点的数量

时间:2018-04-29 12:30:54

标签: opengl-es three.js webgl

使用WebGL API,有没有办法计算给定画布中渲染的顶点数?我已经看到一些试图完成这项任务的工具,但有些工具却给出了奇怪的结果(例如,Three.js'renderer.info.render报告我的场景有10,134.3个三角形)。

使用原始WebGL API计算渲染顶点数(以及理想情况下,点和线)的任何帮助都将非常感激。

2 个答案:

答案 0 :(得分:4)

WebGL无法为您执行此操作,但您可以添加自己的扩充。

最明显的方法是跟踪自己的使用情况。而不是致电commentIdList.map(commentId => ({ [commentId]: comments[commentId] }) 致电gl.drawXXX并自行跟踪这些值。

您还可以扩充WebGL上下文。实施例



functionThatTracksDrawingCountsXXX

// 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();
  }
}
&#13;
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; }
&#13;
&#13;
&#13;

当然,您可能希望添加对drawArraysInstanced等的支持...以及对WebGL2的支持。

答案 1 :(得分:1)

我们从renderer.info.render中删除了已处理顶点的数量,因为重要的测量值是数量或渲染的图元(所以三角形,点,线)。有关更多信息,请阅读https://github.com/mrdoob/three.js/pull/13404以及相关问题/ PR。如果您仍想知道处理了多少个顶点,则需要手动计算。 WebGL无法为您做到这一点。