Search code examples
javascriptthree.jspoint-clouds

How do you pick individual points from THREE.Points object?


I have a point cloud represented by a single THREE.Points(). I'm looking to to pick individual points out with mouse clicks.

    starsGeometry = new THREE.Geometry();

    for ( var i = 0; i < 10000; i ++ ) {
        var star = new THREE.Vector3();
        star.x = THREE.Math.randFloatSpread( 100 );
        star.y = THREE.Math.randFloatSpread( 100 );
        star.z = THREE.Math.randFloatSpread( 100 );
        starsGeometry.vertices.push( star );
    }

    var starsMaterial = new THREE.PointsMaterial( { color: 0x888888 } );
    starField = new THREE.Points( starsGeometry, starsMaterial );
    scene.add( starField );

My picking code is this, but it unfortunately just pick the whole Points object

  mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

    raycaster.setFromCamera( mouse, camera );

    // calculate objects intersecting the picking ray
    var intersects = raycaster.intersectObjects( scene.children );

    for ( var i = 0; i < intersects.length; i++ ) {

        intersects[ i ].object.material.color.set( 0xff0000 );

    }

Solution

  • Step 1:

    Changing material.color is going to affect all points, not just one. If you want to set up an independent color for each point, you'll have to follow something like this example. The key takeaway is that you'll have to use the Geometry.colors array to assign each point's color, just like you did with each point's position. This way you can individually change it when the raycasting occurs. Then, when creating the material, you tell it to read the individual vertex colors with THREE.VertexColors:

    THREE.PointsMaterial({ vertexColors: THREE.VertexColors });

    Step 2:

    Each time your raycaster intersects something, you get an object with several attributes:

    { distance, point, face, faceIndex, object, uv, instanceId }

    As you've discovered, the object property is all points, but you can use point property to get the Vec3 position of where the intersection occurred. You'll need to loop through your geometry.vertices array to find the closest one, but once you find it, you can change its color with the geometry.color attribute you established in step 1.