Reputation: 381
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/
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:
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
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
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
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