currenthandle
currenthandle

Reputation: 1316

Add Points to a Point Cloud with User Mouse Clicks

I'm using Three.js to render point cloud data retrieved from a server.

For each data set, I loop over the data points and create a Three.js Vector3 object with x, y & z values corresponding to each data point. I push each of these vertices onto a list which I then pass into the vertices prop of my geometry component within my points component.

render() {
    this.pointCloudVertices = [];
    if (this.props.points) {
        const points = this.props.points
        for (let i = 0; i < points.x.length; i++) {
            const vertex = new THREE.Vector3();

            vertex.x = points.x[i]
            vertex.y = points.y[i]
            vertex.z = points.z[i]

            this.pointCloudVertices.push(vertex);
        }
    }
    return (<points>
        <geometry vertices={this.pointCloudVertices}/>
        <pointsMaterial
            color={ (Math.floor(Math.random()*16777215)) }
            size={ 0.2 }
        />
    </points>);
}

https://github.com/caseysiebel/pc-client/blob/master/src/components/PointCloud.js

I'd like the user to be able to use their mouse to add points to another point cloud (points component) by clicking inside the canvas.

I found a lot of resources pointing to the Three.js' Raycaster, but this tool seems to be more for selecting out objects already in the canvas. In my case I'd like the user to be able to click on and area in the canvas not occupied by an object, have the client work out the x, y & z coordinates of that click and then add a vertex, with those x/y/z values, to a points component (likely empty until the user adds points via this modality).

I'm a little confused as to how I will convert 2D mouse events into a 3D vertex value. If anyone knows any good resources on this subject I'd love to check them out.

Upvotes: 0

Views: 572

Answers (1)

prisoner849
prisoner849

Reputation: 17596

With THREE.Raycaster(), I see several solutions:

1. Use the .at() method of the .ray property. Like this:

raycaster.ray.at(100 + Math.random() * 150, rndPoint);

Here you can set the constraints for the distance from the origin of the ray, and it will look like this from your original camera:

front camera view

and how it will look like from aside:

free camera view

jsfiddle example. You can switch the lines off there.

2. Use the .intersectObjects() method. Where intersecting objects are planes of constraints. For example, we have planes in the form of a cube. When we cast a ray through them, we always intersect two planes, and the array of intersectec objects will be sorted by distance from the origin of the ray. Thus the first element in this array will be the closest plane. So, when we know it, we can take their points of intersection and sub point1 from point2, getting a new vector (its length and direction). And then we'll just set a point at a random place along the vector from point1 to point2:

intersected = raycaster.intersectObjects(planes.children);
  if (intersected.length > 0){
    var point1 = intersected[0].point;
    var point2 = intersected[1].point;
    var diff = point2.clone().sub(point1);
    var diffLength = diff.length();
    rndPoint = point1.clone().addScaledVector(diff.normalize(), Math.random() * diffLength);
    . . .
  }

It will look like this from the front camera:

front camera view

and from aside:

free camera view

jsfiddle example. Lines are switchable here too.

Or you can use THREE.Raycaster() with THREE.OrthographicCamera(). Which is simplier )

Upvotes: 1

Related Questions