Daniel Kocevski
Daniel Kocevski

Reputation: 381

Advice on Improving ThreeJS Performance

I'm the lead developer for NASA's new gamma-ray constellations page, which is an interactive outreach tool to highlight what the night sky looks like at different wavelengths:

https://fermi.gsfc.nasa.gov/science/constellations/

Screenshot of the gamma-ray constellation page

I used ThreeJS to put together the interactive content and while the page works fine on a modern laptop, I've been seeking ways to improve performance on older devices as well as mobile platforms.

My apologies if this is too broad of a question, but I would appreciate any comments on how to improve the efficiency of ThreeJS in such an application. In particular, I'm curious to hear how experienced ThreeJS coders would potentially consolidate/merge geometries to cut down on CPU/memory overhead. I'm a scientist pulling double duty as a programmer, so any suggestions on how to improve the performance of the current code would be greatly appreciated.

Here's a basic breakdown of how the interactive scene is constructed, but the full code can be found at the link above:

  1. Create and texture a "sky" sphere
  2. Position the camera inside the sphere
  3. Create grid lines along the sphere
  4. Create the optical constellation lines
  5. Create the gamma-ray constellation lines
  6. Create geometries to contain the constellation art
  7. Create transparent click capture geometries to toggle constellation art

The final product has 1083 geometries, 75 textures, 125336 vertices, and 40642 faces. Viewing the page on my 2016 MacBook Pro for a few minutes will heat it up enough to fry an egg. Any suggestions on best practices to make the code more efficient would be appreciated.

Upvotes: 15

Views: 12050

Answers (3)

Pawel
Pawel

Reputation: 18212

The first thing I noticed are grid lines which create 70 draw calls. Then constellations which consist of multiple lines.

For the grid I'd use a custom shader like the one below and make a smaller sphere inside the main one with additive blending https://2pha.com/demos/threejs/shaders/simple_lines.html

For the constellations I'd either use LineSegments or render groups of lines into textures and use these in the scene https://threejsfundamentals.org/threejs/lessons/threejs-rendertargets.html

Upvotes: 0

WestLangley
WestLangley

Reputation: 104783

You are currently rendering the scene 60 times per second. Your biggest improvement in performance should be achieved by rendering only when needed.

For a static scene, you only need to render when the camera moves -- an animation loop is not required.

For example, if you were using OrbitControls to control your camera, you would use this pattern.

var controls = new THREE.OrbitControls( camera, renderer.domElement );

// call this only in static scenes (i.e., if there is no animation loop)
controls.addEventListener( 'change', render ); 

Also, even though you are using TWEEN in your demo, you can instantiate an animation loop only for the duration of the tween by using a pattern like so:

// start animate loop
var id;
animate();

// tween
var time = { t: 0 };
new TWEEN.Tween( time )
    .to( { t : 1 }, 1000 )
    .onStart( function() {
        // custom
    } )
    .onUpdate( function() {
        // custom
    } )
    .onComplete( function() {
        // custom
        cancelAnimationFrame( id );
    } )
    .start();

function animate() {

    id = requestAnimationFrame( animate );

    TWEEN.update();

    render();

}

function render() {

    renderer.render( scene, camera );

}

three.js r.97

Upvotes: 11

Mugen87
Mugen87

Reputation: 31026

Depending on the view position and angle, your app produces up to 600 draw calls per frame. You can easily see this by typing renderer.info.render in the browser console. A good starting point in context of performance optimization is the reduction of draw calls. You can do this in several ways e.g. by merging multiple geometries into a single one, using instanced rendering or avoiding multi material objects. If your application is CPU bound, reducing draw calls can greatly improve the performance of a 3D application.

Since you are using three.js R84, I suggest you upgrade to the latest version. We implemented this year some performance features like uniform caching or avoid redundant state changes in context of blending. Stuff like that might also have a positive impact on your app's performance.

BTW: There are many interesting discussion about performance optimization in the three.js forum.

Upvotes: 7

Related Questions