Come ottenere oggetti nello spazio 3D WebGL da una coordinata di clic del mouse

Sto costruendo un gioco da tavolo in WebGL. La scheda può essere ruotata / ingrandita. Ho bisogno di un modo per tradurre un clic sull’elemento canvas (x, y) nel punto rilevante nello spazio 3D (x, y, z). Il risultato finale è che voglio conoscere la coordinata (x, y, z) che contiene il punto che tocca l’object più vicino all’utente. Ad esempio, l’utente fa clic su un pezzo e immagina un raggio che percorre lo spazio 3D che attraversa sia il pezzo che il tabellone di gioco, ma io voglio il (x, y, z) coord del pezzo nel punto in cui era toccato.

Credo che questo debba essere un problema molto comune, ma non riesco a trovare una soluzione nei miei googles. Ci deve essere un modo per proiettare la vista corrente dello spazio 3D in 2D in modo da poter mappare ogni punto nello spazio 2D al punto pertinente nello spazio 3D. Voglio che l’utente sia in grado di passare il mouse su uno spazio sulla scacchiera e che lo spot cambi colore.

Stai cercando una funzione non project, che converte le coordinate dello schermo in un cast di raggio dalla posizione della telecamera al mondo 3D. È quindi necessario eseguire test di intersezione raggio / triangolo per trovare il triangolo più vicino alla telecamera che interseca anche il raggio.

Ho un esempio di non proiezione disponibile su jax / camera.js # L568 – ma dovrai ancora implementare l’intersezione raggio / triangolo. Ne ho un’implementazione su jax / triangle.js # L113 .

Esiste un’alternativa più semplice e (solitamente) più veloce, tuttavia, chiamata “picking”. Usalo se vuoi selezionare un intero object (ad esempio, un pezzo degli scacchi), e se non ti interessa dove il mouse ha effettivamente cliccato. Il modo in cui WebGL è quello di rendere l’intera scena in varie tonalità di blu (il blu è una chiave, mentre il rosso e il verde sono usati per gli ID univoci degli oggetti nella scena) a una trama, quindi rileggere un pixel da quella trama. Decodificare l’RGB nell’ID dell’object ti darà l’object su cui è stato fatto clic. Ancora una volta, ho implementato questo ed è disponibile su jax / world.js # L82 . (Vedi anche linee 146, 162, 175.)

Entrambi gli approcci hanno pro e contro (discussi qui e in alcuni dei commenti successivi) e dovrai capire quale approccio è più adatto alle tue esigenze. Il picking è più lento con scene gigantesche, ma la proiezione non programmata in JS puro è estremamente lenta (dal momento che JS non è poi così veloce), quindi la mia migliore raccomandazione sarebbe quella di sperimentare con entrambi.

Per tua informazione, potresti anche guardare il progetto GLU e il codice non progetto, su cui ho basato il mio codice liberamente: http://www.opengl.org/wiki/GluProject_and_gluUnProject_code

Questa è la demo funzionante

function onMouseUp(event) { event.preventDefault(); x_pos = (event.clientX / window.innerWidth) * 2 - 1; y_pos = -(event.clientY / window.innerHeight) * 2 + 1; z_pos = 0.5; var vector = new THREE.Vector3( x_pos , y_pos , z_pos ); var projector = new THREE.Projector(); projector.unprojectVector(vector, camera); var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize()); var intersects = raycaster.intersectObjects(intersectObjects); if (intersects.length > 0) { xp = intersects[0].point.x.toFixed(2); yp = intersects[0].point.y.toFixed(2); zp = intersects[0].point.z.toFixed(2); destination = new THREE.Vector3( xp , yp , zp ); radians = Math.atan2( ( driller.position.x - xp) , (driller.position.z - zp)); radians += 90 * (Math.PI / 180); console.log(radians); var tween = new TWEEN.Tween(driller.rotation).to({ y : radians },200).easing(TWEEN.Easing.Linear.None).start(); } 

weissner-doors.de/drone/

Sto lavorando a questo problema al momento – l’approccio che sto prendendo è

  1. Renderizza oggetti per selezionare il buffer ciascuno con un colore unico
  2. Leggi il pixel del buffer, torna all’object selezionato
  3. Renderizza l’object selezionato per bufferizzare con ciascun colore di pixel una funzione di profondità Z.
  4. Leggi il pixel del buffer, torna a Z-depth
  5. Abbiamo scelto l’object e approssimativo Z per i pick coord

cultato da uno dei fili. non sono sicuro di (x, y, z) ma puoi ottenere il canvas(x,y) usando

getBoundingClientRect ()

 function getCanvasCoord(){ var mx = event.clientX; var my = event.clientY; var canvas = document.getElementById('canvasId'); var rect = canvas.getBoundingClientRect();// check if your browser supports this mx = mx - rect.left; my = my - rect.top; return {x: mx , y: my}; }