Skip to main content

SimpleRaycaster

🤏 Touching things


In this tutorial, we'll learn to interact with our scene. This will work both for a mouse 🐀 and for the touch screen of a phone 📱 or tablet 🍎. This might sound daunting, but it's actually very easy! Let's see how to do that in 5 minutes.

First, let's set up a simple scene!

If you haven't started there, check out that tutorial first!

Next, we will add some objects to pick. Specifically, we will add 3 boxes of different colors using Three.js API. To do that, first we need to create 4 materials: one material per box, and a fourth material to highlight boxes that we pick:

const redMaterial = new THREE.MeshStandardMaterial({ color: 'red' });
const greenMaterial = new THREE.MeshStandardMaterial({ color: 'green' });
const blueMaterial = new THREE.MeshStandardMaterial({ color: 'blue' });
const yellowMaterial = new THREE.MeshBasicMaterial({ color: 'yellow' });

Great! Now, we will add the geometry itself. For that we need 5 meshes that can share the same cube geometry (as all the geometry of the cubes is the same).

const boxGeometry = new THREE.BoxGeometry(3, 3, 3);
const redCube = new THREE.Mesh(boxGeometry, redMaterial);
const greenCube = new THREE.Mesh(boxGeometry, greenMaterial);
const blueCube = new THREE.Mesh(boxGeometry, blueMaterial);
scene.add(redCube, greenCube, blueCube);
const cubes = [redCube, greenCube, blueCube];

Let's give the cubes a different position so that we can see all of them in the scene:

greenCube.position.x = 5;
blueCube.position.x = -5;

🔄 Spinning up the cubes


To spice things up a little, let's create an animation loop that rotates the cubes each frame. You can do this super easily by creating a function and adding it to the beforeUpdate event of the RendererComponent inside Components using the on() method:

const oneDegree = Math.PI / 180;
function rotateCubes() {
redCube.rotation.x += oneDegree;
redCube.rotation.y += oneDegree;
greenCube.rotation.x += oneDegree;
greenCube.rotation.z += oneDegree;
blueCube.rotation.y += oneDegree;
blueCube.rotation.z += oneDegree;
}
components.renderer.beforeUpdate.on(rotateCubes);
Turning off animations

You can turn off animations simply by using the off() method. This works for any event in the library! ⌚

⚡ Casting rays around


Awesome! Now, when we pick a cube, we will substitute the original material by the yellow material. Afterwards, we will need a way to get back the original material. We can easily achieve this by adding a reference to the material in the userData property, which is an object where you can add any data you need:

redCube.userData.originalMaterial = redMaterial;
greenCube.userData.originalMaterial = greenMaterial;
blueCube.userData.originalMaterial = blueMaterial;

Finally, we will use the raycaster. This is very easy using the raycaster component, which solves this for all screen sizes. We will create an event that fires every time that the user moves the mouse. 👇

How does it really work?

We will simply reset the material of the previous selection (if it exists), and then apply the yellow material to the found object (if any). This might sound like a lot, but it's actually very little code. 😉

let previousSelection;
window.onmousemove = () => {
const result = components.raycaster.castRay(cubes);
if(previousSelection) {
previousSelection.material = previousSelection.userData.originalMaterial;
}
if(!result) {
return;
}
result.object.material = yellowMaterial;
previousSelection = result.object;
}

Great job! 🎉 Now you know how to pick geometry in your 3D scene using a raycaster component component! 💪 You are now one step closer to build your own BIM software. Let's keep it up and check out another tutorials!