Dynamically adding meshes causes controls to lag

Viewed 141

I am making a 3D map in Three.js.

I am constructing the geometry and texture from fetched 256x256 pixel images, construct a THREE.Mesh and add it to the scene when it's done.

However, adding tiles to the map causes MapControls to lag noticeably, if the user is panning or zooming around quickly. This can be alleviated by using smaller tiles (such as 128*128), but I want to find a better way, as I've seen examples of very smooth maps using Three.js. The controls work smoothly after all the tiles in view have loaded.

I have 2 event listeners. One triggers when controls change:

this.controls.addEventListener('change', this.update);

And renders the map:

update = () => {
    this.renderer.render(this.scene, this.camera);
};

The other listens for the move to end, and then fetches the tiles in view:

this.controls.addEventListener('end', this.fetchTilesIfNecessary);

fetchTilesIfNecessary then creates Promises, which start fetching the tiles. When the tiles are fetched, they are added to the map and this.update is called:

addTile(tile) {
    this.scene.add(tile.mesh);
    this.update();
}

Perhaps I should mention that I have a callback when the tile mesh gets rendered:

this.mesh.onAfterRender = this.disposeAttributes;

Which clears the attributes which are causing a lot of memory usage

disposeAttributes(renderer, scene, camera, geometry, material, group) {
    geometry.getAttribute('position').array = [];
    geometry.getAttribute('normal').array = [];
    geometry.getAttribute('uv').array = [];
}

Is there a better way? How can I add meshes to the scene dynamically and keep the controls running smoothly?

1 Answers

One way to mitigate this issue is to pre-compile all shaders via WebGLRenderer.compile(). Meaning when your app starts, you add all tiles to your scene and then call renderer.compile() once with the scene's camera.

this.mesh.onAfterRender = this.disposeAttributes;

This is not recommended since it will be executed on each render call. If you want to free the geometry data one the JS side, use the onUpdate() callback of BufferAttribute().

geometry.getAttribute( 'position' ).onUpload( disposeArray );

function disposeArray() {

    this.array = null;

}
Related