three.js
Cueillette d'objets
Recherche…
Préparation d'objets / Raycasting
Raycasting signifie lancer un rayon depuis la position de la souris sur l'écran vers la scène. Voici comment troisjs détermine l'objet sur lequel vous souhaitez cliquer si vous l'avez implémenté. Threejs obtient ces informations en utilisant un octree , mais en production, vous ne voudrez peut-être pas calculer le résultat à chaque image ou sur l'événement mousemove
, mais plutôt sur l'événement click
pour une application plus accessible avec des exigences peu élevées.
var raycaster, mouse = { x : 0, y : 0 };
init();
function init () {
//Usual setup code here.
raycaster = new THREE.Raycaster();
renderer.domElement.addEventListener( 'click', raycast, false );
//Next setup code there.
}
function raycast ( e ) {
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//3. compute intersections
var intersects = raycaster.intersectObjects( scene.children );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ] );
/*
An intersection has the following properties :
- object : intersected object (THREE.Mesh)
- distance : distance from camera to intersection (number)
- face : intersected face (THREE.Face3)
- faceIndex : intersected face index (number)
- point : intersection point (THREE.Vector3)
- uv : intersection point in the object's UV coordinates (THREE.Vector2)
*/
}
}
MISE EN GARDE! Vous risquez de perdre votre temps à regarder l'écran vide si vous ne lisez pas la partie suivante.
Si vous souhaitez détecter l'assistant, définissez le deuxième paramètre de raycaster.intersectObjects( scene.children );
à vrai.
Cela signifie raycaster.intersectObjects( scene.children , true);
Le code raycast ne détectera que l'assistant.
Si vous souhaitez qu’il détecte les objets normaux ainsi que les aides à la lumière, vous devez copier à nouveau la fonction Raycast ci-dessus. Voir cette question .
Le code raycast complet est
function raycast ( e ) {
// Step 1: Detect light helper
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//3. compute intersections (note the 2nd parameter)
var intersects = raycaster.intersectObjects( scene.children, true );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ] );
/*
An intersection has the following properties :
- object : intersected object (THREE.Mesh)
- distance : distance from camera to intersection (number)
- face : intersected face (THREE.Face3)
- faceIndex : intersected face index (number)
- point : intersection point (THREE.Vector3)
- uv : intersection point in the object's UV coordinates (THREE.Vector2)
*/
}
// Step 2: Detect normal objects
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//3. compute intersections (no 2nd parameter true anymore)
var intersects = raycaster.intersectObjects( scene.children );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ] );
/*
An intersection has the following properties :
- object : intersected object (THREE.Mesh)
- distance : distance from camera to intersection (number)
- face : intersected face (THREE.Face3)
- faceIndex : intersected face index (number)
- point : intersection point (THREE.Vector3)
- uv : intersection point in the object's UV coordinates (THREE.Vector2)
*/
}
}
Cueillette d'objets / GPU
La sélection d'objets à l'aide de Raycasting peut être une tâche lourde pour votre CPU en fonction de votre configuration (par exemple, si vous n'avez pas de configuration similaire à l'octree) et du nombre d'objets dans la scène.
Si vous n'avez pas besoin des coordonnées du monde sous le curseur de la souris, mais uniquement pour identifier l'objet sous celui-ci, vous pouvez utiliser la sélection GPU.
Brève explication, GPU peut être un outil puissant pour le calcul mais vous devez savoir comment récupérer les résultats. L'idée est que si vous restituez les objets avec une couleur qui représente leur identifiant, vous pouvez lire la couleur du pixel sous le curseur et trouver l'identifiant de l'objet qui est sélectionné. Rappelez-vous que RVB est juste une valeur hexadécimale donc il existe une conversion entre id (entier) et couleur (hex).
- Créer une nouvelle scène et une nouvelle cible de rendu pour votre objet
var pickingScene = new THREE.Scene();
var pickingTexture = new THREE.WebGLRenderTarget(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
pickingTexture.texture.minFilter = THREE.LinearFilter;
- Créer un nouveau matériau Matériau pour la sélection d'objets;
var vs3D = `
attribute vec3 idcolor;
varying vec3 vidcolor;
void main(){
vidcolor = idcolor;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0);
}`;
var fs3D = `
varying vec3 vidcolor;
void main(void) {
gl_FragColor = vec4(vidcolor,1.0);
}`;
var pickingMaterial = new THREE.ShaderMaterial(
{
vertexShader: vs3D,
fragmentShader: fs3D,
transparent: false,
side: THREE.DoubleSide
});
- Ajoutez vos géométries maillage / ligne à un nouvel attribut qui représente leur identifiant en RVB, créez l'objet pickingObject en utilisant la même géométrie et ajoutez-le à la scène de sélection, puis ajoutez le maillage réel à un dictionnaire d'objets id->
var selectionObjects = [];
for(var i=0; i<myMeshes.length; i++){
var mesh = myMeshes[i];
var positions = mesh.geometry.attributes["position"].array;
var idColor = new Float32Array(positions.length);
var color = new THREE.Color();
color.setHex(mesh.id);
for (var j=0; j< positions.length; j+=3){
idColor[j] = color.r;
idColor[j+1] = color.g;
idColor[j+2] = color.b;
}
mesh.geometry.addAttribute('idcolor', new THREE.BufferAttribute(idColor, 3));
var pickingObject = new THREE.Mesh(mesh.geometry, pickingMaterial);
pickingScene.add(pickingObject);
selectionObjects[mesh.id] = mesh;
}
- Enfin, sur votre souris, cliquez sur le gestionnaire
renderer.render(pickingScene, camera, pickingTexture);
var pixelBuffer = new Uint8Array(4);
renderer.readRenderTargetPixels(pickingTexture, event.pageX, pickingTexture.height - event.pageY, 1, 1, pixelBuffer);
var id = (pixelBuffer[0] << 16) | (pixelBuffer[1] << 8) | (pixelBuffer[2]);
if (id>0){
//this is the id of the picked object
}else{
//it's 0. clicked on an empty space
}