Как отрендерить менее затратную сферу в кадре / три js? - PullRequest
1 голос
/ 29 мая 2020

У меня есть приложение vr, которое отображает множество сфер. Встроенный элемент aframe <a-sphere> визуализирует сферы с помощью треугольников, и в результате моя сцена имеет массу треугольников. Это убивает производительность, снижая частоту кадров до подростковой. Можно ли использовать более эффективный объект, подобный сфере? Этим сферам действительно не нужно делать ничего особенного, я готов пожертвовать их внешним видом, чтобы иметь возможность отображать их больше без потери производительности.

1 Ответ

3 голосов
/ 30 мая 2020

Вы можете прибегнуть к InstancedMesh, который использует создание экземпляров графического процессора для рендеринга повторяющейся геометрии за один вызов отрисовки.

Посмотрите демо ниже. Рендеринг 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>

Щелкните здесь, чтобы увидеть исходный код демонстрации

...