【问题标题】:WebGL: Count the number of rendered verticesWebGL:计算渲染顶点的数量
【发布时间】:2018-04-30 20:50:06
【问题描述】:

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

如果能帮助您使用原始 WebGL API 计算渲染顶点(理想情况下是点和线)的数量,我们将不胜感激。

【问题讨论】:

    标签: opengl-es three.js webgl


    【解决方案1】:

    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; }
    <canvas></canvas>
    <div id="ui">
      <pre id="count"></pre>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>

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

    【讨论】:

    • 根据其他答案,顶点是否是一个有效的测量对象? (三角形、点、线)
    【解决方案2】:

    我们从renderer.info.render 中删除了已处理顶点的数量,因为重要的测量是数量或渲染的图元(如三角形、点、线)。请阅读https://github.com/mrdoob/three.js/pull/13404 和相关问题/PR 以获取更多信息。如果还想知道处理了多少个顶点,则需要手动统计。 WebGL 无法为您执行此操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多