performance3dthree.js

Rendering a large number of colored particles using three.js and the canvas renderer


I am trying to use the Three.js library to display a large number of colored points on the screen (about half a million to million for example). I am trying to use the Canvas renderer rather than the WebGL renderer if possible (The web pages would also be displayed in the Google Earth Client bubbles, which seems to work with Canvas renderer but not the WebGL renderer.)

While I have the problem solved for a small number of points (tens of thousands) by modifying the code from here, I am having trouble scaling it beyond that.

But in the the following code using WebGL and the Particle System I can render half a million random points, but without colors.

  ...
var particles = new THREE.Geometry();
var pMaterial = new THREE.ParticleBasicMaterial({
                    color: 0xFFFFFF,
                    size: 1,
                    sizeAttenuation : false
                    });

// now create the individual particles
for (var p = 0; p < particleCount; p++) {
     // create a particle with randon position values,
     // -250 -> 250
     var pX = Math.random() * POSITION_RANGE - (POSITION_RANGE / 2),
     pY = Math.random() * POSITION_RANGE - (POSITION_RANGE / 2),
     pZ = Math.random() * POSITION_RANGE - (POSITION_RANGE / 2),
     particle = new THREE.Vertex(
                        new THREE.Vector3(pX, pY, pZ)
                        );

     // add it to the geometry
     particles.vertices.push(particle);
    }

    var particleSystem = new THREE.ParticleSystem(
                            particles, pMaterial);
    scene.add(particleSystem);
  ...

Is the reason for the better performance of the above code due to the Particle System? From what I have read in the documentation it seems the Particle System can only be used by the WebGL renderer.

So my question(s) are

a) Can I render such large number of particles using the Canvas renderer or is it always going to be slower than the WebGL/ParticleSystem version? If so, how do I go about doing that? What objects and or tricks do I use to improve performance?

b) Is there a compromise I can reach if I give up some features? In other words, can I still use the Canvas renderer for the large dataset if I give up the need to color the individual points?

c) If I have to give up the Canvas and use the WebGL version, is it possible to change the colors of the individual points? It seems the color is set by the material passed to the ParticleSystem and that sets the color for all the points.


Solution

  • EDIT: ParticleSystem and PointCloud has been renamed to Points. In addition, ParticleBasicMaterial and PointCloudMaterial has been renamed to PointsMaterial.

    This answer only applies to versions of three.js prior to r.125.

    To have a different color for each particle, you need to have a color array as a property of the geometry, and then set vertexColors to THREE.VertexColors in the material, like so:

    // vertex colors
    const colors = [];
    for( let i = 0; i < geometry.vertices.length; i++ ) {
    
        // random color
        colors[i] = new THREE.Color();
        colors[i].setHSL( Math.random(), 1.0, 0.5 );
    
    }
    geometry.colors = colors;
    
    // material
    const material = new THREE.PointsMaterial( {
        size: 10,
        transparent: true,
        opacity: 0.7,
        vertexColors: THREE.VertexColors
    } );
    
    // point cloud
    const pointCloud = new THREE.Points( geometry, material );
    

    Your other questions are a little too general for me to answer, and besides, it depends on exactly what you are trying to do and what your requirements are. Yes, you can expect Canvas to be slower.

    EDIT: Updated for three.js r.124