usar three particulas libreria learn how ejemplos detector con como three.js point projection ray mouse-coordinates

three.js - particulas - three.min.js download



Mouse/Canvas X, Y a Three.js World X, Y, Z (8)

Aquí está mi opinión sobre cómo crear una clase de es6. Trabajando con Three.js r83. El método de usar rayCaster proviene de mrdoob aquí: Proyector Three.js y objetos Ray

export default class RaycasterHelper { constructor (camera, scene) { this.camera = camera this.scene = scene this.rayCaster = new THREE.Raycaster() this.tapPos3D = new THREE.Vector3() this.getIntersectsFromTap = this.getIntersectsFromTap.bind(this) } // objects arg below needs to be an array of Three objects in the scene getIntersectsFromTap (tapX, tapY, objects) { this.tapPos3D.set((tapX / window.innerWidth) * 2 - 1, -(tapY / window.innerHeight) * 2 + 1, 0.5) // z = 0.5 important! this.tapPos3D.unproject(this.camera) this.rayCaster.set(this.camera.position, this.tapPos3D.sub(this.camera.position).normalize()) return this.rayCaster.intersectObjects(objects, false) } }

Lo usarías así si quisieras comparar todos tus objetos en la escena con los golpes. Hice la bandera recursiva falsa arriba porque para mis usos no la necesitaba.

var helper = new RaycasterHelper(camera, scene) var intersects = helper.getIntersectsFromTap(tapX, tapY, this.scene.children) ...

He buscado un ejemplo que coincida con mi caso de uso pero no puedo encontrar uno. Estoy tratando de convertir las coordenadas del mouse de la pantalla en coordenadas mundiales 3D teniendo en cuenta la cámara.

Soluciones que he encontrado todas intersección de rayos para lograr la selección de objetos.

Lo que intento hacer es ubicar el centro de un objeto Three.js en las coordenadas que el mouse está "sobre" en ese momento.

Mi cámara está en x: 0, y: 0, z: 500 (aunque se moverá durante la simulación) y todos mis objetos están en z = 0 con valores variables de xey, por lo que necesito conocer el mundo X, Y suponiendo que az = 0 para el objeto que seguirá la posición del mouse.

Esta pregunta parece un problema similar, pero no tiene una solución: obtener las coordenadas del mouse en relación con el espacio 3D en THREE.js

Dada la posición del mouse en la pantalla con un rango de "top-left = 0, 0 | bottom-right = window.innerWidth, window.innerHeight", ¿alguien puede proporcionar una solución para mover un objeto Three.js a las coordenadas del mouse? a lo largo de z = 0?


Aunque las respuestas proporcionadas pueden ser útiles en algunos escenarios, difícilmente puedo imaginar esos escenarios (quizás juegos o animaciones) porque no son del todo precisos (¿adivinando alrededor del NDC z del objetivo?). No puede usar esos métodos para desprogramar las coordenadas de pantalla a las del mundo si conoce el plano z del objetivo. Pero para la mayoría de los escenarios, debes saber este plano.

Por ejemplo, si dibuja esfera por centro (punto conocido en el espacio modelo) y radio - necesita obtener el radio como delta de coordenadas de mouse no proyectadas - ¡pero no puede! Con todo el respeto @ El método de WestLangley con targetZ no funciona, da resultados incorrectos (puedo proporcionar jsfiddle si es necesario). Otro ejemplo: debe establecer el objetivo de los controles de la órbita con doble clic del mouse, pero sin emisión de rayos "real" con objetos de escena (cuando no tiene nada que elegir).

La solución para mí es simplemente crear el plano virtual en el punto objetivo a lo largo del eje z y usar el raycasting con este plano después. El punto de destino puede ser la órbita actual que controla el objetivo o el vértice del objeto que necesita dibujar paso a paso en el espacio modelo existente, etc. Esto funciona a la perfección y es simple (ejemplo en texto mecanografiado):

screenToWorld(v2D: THREE.Vector2, camera: THREE.PerspectiveCamera = null, target: THREE.Vector3 = null): THREE.Vector3 { const self = this; const vNdc = self.toNdc(v2D); return self.ndcToWorld(vNdc, camera, target); } //get normalized device cartesian coordinates (NDC) with center (0, 0) and ranging from (-1, -1) to (1, 1) toNdc(v: THREE.Vector2): THREE.Vector2 { const self = this; const canvasEl = self.renderers.WebGL.domElement; const bounds = canvasEl.getBoundingClientRect(); let x = v.x - bounds.left; let y = v.y - bounds.top; x = (x / bounds.width) * 2 - 1; y = - (y / bounds.height) * 2 + 1; return new THREE.Vector2(x, y); } ndcToWorld(vNdc: THREE.Vector2, camera: THREE.PerspectiveCamera = null, target: THREE.Vector3 = null): THREE.Vector3 { const self = this; if (!camera) { camera = self.camera; } if (!target) { target = self.getTarget(); } const position = camera.position.clone(); const origin = self.scene.position.clone(); const v3D = target.clone(); self.raycaster.setFromCamera(vNdc, camera); const normal = new THREE.Vector3(0, 0, 1); const distance = normal.dot(origin.sub(v3D)); const plane = new THREE.Plane(normal, distance); self.raycaster.ray.intersectPlane(plane, v3D); return v3D; }


Debajo hay una clase de ES6 que escribí basada en la respuesta de WestLangley, que funciona perfectamente para mí en THREE.js r77.

Tenga en cuenta que asume que su ventana gráfica de renderizado ocupa toda su vista del navegador.

class CProjectMousePosToXYPlaneHelper { constructor() { this.m_vPos = new THREE.Vector3(); this.m_vDir = new THREE.Vector3(); } Compute( nMouseX, nMouseY, Camera, vOutPos ) { let vPos = this.m_vPos; let vDir = this.m_vDir; vPos.set( -1.0 + 2.0 * nMouseX / window.innerWidth, -1.0 + 2.0 * nMouseY / window.innerHeight, 0.5 ).unproject( Camera ); // Calculate a unit vector from the camera to the projected position vDir.copy( vPos ).sub( Camera.position ).normalize(); // Project onto z=0 let flDistance = -Camera.position.z / vDir.z; vOutPos.copy( Camera.position ).add( vDir.multiplyScalar( flDistance ) ); } }

Puedes usar la clase de esta manera:

// Instantiate the helper and output pos once. let Helper = new CProjectMousePosToXYPlaneHelper(); let vProjectedMousePos = new THREE.Vector3(); ... // In your event handler/tick function, do the projection. Helper.Compute( e.clientX, e.clientY, Camera, vProjectedMousePos );

vProjectedMousePos ahora contiene la posición proyectada del mouse en el plano z = 0.


En r.58 este código funciona para mí:

var planeZ = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); var mv = new THREE.Vector3( (event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5 ); var raycaster = projector.pickingRay(mv, camera); var pos = raycaster.ray.intersectPlane(planeZ); console.log("x: " + pos.x + ", y: " + pos.y);


Esto funcionó para mí cuando usé una orthographic camera

let vector = new THREE.Vector3(); vector.set( (event.clientX / window.innerWidth) * 2 - 1, - (event.clientY / window.innerHeight) * 2 + 1, 0 ); vector.unproject(camera);

WebGL three.js r.89


No necesita tener ningún objeto en su escena para hacer esto.

Usted ya conoce la posición de la cámara.

Usando el proyecto vector.unproject( camera ) puede obtener un rayo apuntando en la dirección que desee.

Solo necesita extender ese rayo, desde la posición de la cámara, hasta que la coordenada z de la punta del rayo sea cero.

Puedes hacer eso así:

var vector = new THREE.Vector3(); vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); vector.unproject( camera ); var dir = vector.sub( camera.position ).normalize(); var distance = - camera.position.z / dir.z; var pos = camera.position.clone().add( dir.multiplyScalar( distance ) );

La variable pos es la posición del punto en el espacio 3D, "debajo del mouse", y en el plano z=0 .

EDITAR: actualizado para three.js r.69


ThreeJS está lentamente cortando el proyector. (Un) ProjectVector y la solución con projector.pickingRay () ya no funciona, acaba de actualizar mi propio código ... así que la versión de trabajo más reciente debería ser la siguiente:

var rayVector = new THREE.Vector3(0, 0, 0.5); var camera = new THREE.PerspectiveCamera(fov,this.offsetWidth/this.offsetHeight,0.1,farFrustum); var raycaster = new THREE.Raycaster(); var scene = new THREE.Scene(); //... function intersectObjects(x, y, planeOnly) { rayVector.set(((x/this.offsetWidth)*2-1), (1-(y/this.offsetHeight)*2), 1).unproject(camera); raycaster.set(camera.position, rayVector.sub(camera.position ).normalize()); var intersects = raycaster.intersectObjects(scene.children); return intersects; }


para obtener las coordenadas del mouse de un objeto 3d usa projectVector:

var width = 640, height = 480; var widthHalf = width / 2, heightHalf = height / 2; var projector = new THREE.Projector(); var vector = projector.projectVector( object.matrixWorld.getPosition().clone(), camera ); vector.x = ( vector.x * widthHalf ) + widthHalf; vector.y = - ( vector.y * heightHalf ) + heightHalf;

para obtener las coordenadas tridimensionales de three.js que se relacionan con las coordenadas específicas del mouse, use el opuesto, unprojectVector:

var elem = renderer.domElement, boundingRect = elem.getBoundingClientRect(), x = (event.clientX - boundingRect.left) * (elem.width / boundingRect.width), y = (event.clientY - boundingRect.top) * (elem.height / boundingRect.height); var vector = new THREE.Vector3( ( x / WIDTH ) * 2 - 1, - ( y / HEIGHT ) * 2 + 1, 0.5 ); projector.unprojectVector( vector, camera ); var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() ); var intersects = ray.intersectObjects( scene.children );

Hay un gran ejemplo here . Sin embargo, para usar el vector del proyecto, debe haber un objeto donde el usuario hizo clic. intersects será una matriz de todos los objetos en la ubicación del mouse, independientemente de su profundidad.