如何在 aframe/three js 中渲染成本较低的球体?

How to render a less costly sphere in aframe/three js?

我有一个渲染很多球体的 VR 应用程序。内置的 aframe <a-sphere> 元素使用三角形渲染球体,因此我的场景有大量三角形。这正在扼杀性能,将帧速率降低到十几岁。我可以使用更有效的球体之类的对象吗?这些球体真的不需要做任何特别的事情,我愿意牺牲它们的外观,以便能够在不影响性能的情况下渲染更多球体。

您可以求助于 InstancedMesh,它使用 GPU 实例化在单个绘图调用中渲染重复的几何图形。

查看下面的演示。渲染 1000 个元素通常需要 1000 个单独的绘图调用,这会大大降低性能。但是通过实例化,您可以在同一个通道中渲染所有这些。

var camera, scene, renderer, stats;

   var mesh;
   var amount = parseInt( window.location.search.substr( 1 ) ) || 10;
   var count = Math.pow( amount, 3 );
   var dummy = new THREE.Object3D();

   init();
   animate();

   function init() {

    camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 100 );
    camera.position.set( amount * 0.9, amount * 0.9, amount * 0.9 );
    camera.lookAt( 0, 0, 0 );

    scene = new THREE.Scene();

    var loader = new THREE.BufferGeometryLoader();
    loader.load( 'https://raw.githubusercontent.com/mrdoob/three.js/master/examples/models/json/suzanne_buffergeometry.json', function ( geometry ) {

     geometry.computeVertexNormals();
     geometry.scale( 0.5, 0.5, 0.5 );

     var material = new THREE.MeshNormalMaterial();
     // check overdraw
     // var material = new THREE.MeshBasicMaterial( { color: 0xff0000, opacity: 0.1, transparent: true } );

     mesh = new THREE.InstancedMesh( geometry, material, count );
     mesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage ); // will be updated every frame
     scene.add( mesh );

     //

     var gui = new dat.GUI();
     gui.add( mesh, 'count', 0, count );

    } );

    //

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    //

    stats = new Stats();
    document.body.appendChild( stats.dom );

    //

    window.addEventListener( 'resize', onWindowResize, false );

   }

   function onWindowResize() {

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize( window.innerWidth, window.innerHeight );

   }

   //

   function animate() {

    requestAnimationFrame( animate );

    render();

    stats.update();

   }

   function render() {

    if ( mesh ) {

     var time = Date.now() * 0.001;

     mesh.rotation.x = Math.sin( time / 4 );
     mesh.rotation.y = Math.sin( time / 2 );

     var i = 0;
     var offset = ( amount - 1 ) / 2;

     for ( var x = 0; x < amount; x ++ ) {

      for ( var y = 0; y < amount; y ++ ) {

       for ( var z = 0; z < amount; z ++ ) {

        dummy.position.set( offset - x, offset - y, offset - z );
        dummy.rotation.y = ( Math.sin( x / 4 + time ) + Math.sin( y / 4 + time ) + Math.sin( z / 4 + time ) );
        dummy.rotation.z = dummy.rotation.y * 2;

        dummy.updateMatrix();

        mesh.setMatrixAt( i ++, dummy.matrix );

       }

      }

     }

     mesh.instanceMatrix.needsUpdate = true;

    }

    renderer.render( scene, camera );

   }
html, body {margin: 0; padding: 0;overflow: hidden;}
<!DOCTYPE html>
<html lang="en">
 <head>
  <title>three.js webgl - instancing - dynamic</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  <script src="https://cdn.jsdelivr.net/npm/three@0.117.1/build/three.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/stats.js@0.17.0/build/stats.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/three@0.117.1/examples/js/libs/dat.gui.min.js"></script>
 </head>
 <body>

 </body>
</html>

Click here to see demo source