Вы можете прибегнуть к 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>
Щелкните здесь, чтобы увидеть исходный код демонстрации