Estoy tratando de obtener coordenadas mundiales haciendo clic en la pantalla, pero usando mapas de desplazamiento. Esto lo hace más complejo ya que el piso tiene alturas variables (colinas). Mi enfoque hasta ahora es calcular el punto en el piso (suponiendo que el piso era todo plano en z = 0), luego rastrear el rayo desde la cámara hasta ese punto, y en cada iteración ver dónde la altura del rayo se convierte en <= el altura real del piso en ese punto. Una vez que es menor o igual a, sabemos que golpeó el piso y tenemos (x,y,z). Los puntos fuera del mapa también tienen z=0.
Este es el código:
// https://stackoverflow.com/questions/13055214/mouse-canvas-xy-to-three-js-world-xyz public static Get3DPoints(camera:THREE.PerspectiveCamera, click_position:THREE.Vector2, targetZ:number) { var vec = new THREE.Vector3(); // create once and reuse var pos = new THREE.Vector3(); // create once and reuse vec.set( ( click_position.x / window.innerWidth ) * 2 - 1, - ( click_position.y / window.innerHeight ) * 2 + 1, 0.5 ); vec.unproject( camera ); vec.sub( camera.position ).normalize(); var distance = ( targetZ - camera.position.z ) / vec.z; pos.copy( camera.position ).add( vec.multiplyScalar( distance ) ); return pos; } public static async Get3DCoordinatesFromClick(GAME_CONTEXT:Game_Context, camera:THREE.PerspectiveCamera, click_position:THREE.Vector2):Promise<THREE.Vector3> { return new Promise((resolve, reject) => { var start = camera.position.clone(); var collision_point:THREE.Vector3; var point3d = this.Get3DPoints(camera, click_position, 0); //console.log(click_position, " fp --->", point3d); new TWEEN.Tween(start).to({ x:point3d.x, y:point3d.y, z:point3d.z }, 60).onUpdate(vector => { if (vector.x < 0 || vector.y < 0 || vector.x > GAME_CONTEXT.width || vector.y > GAME_CONTEXT.height) { var z = 0; } else { var z = GAME_CONTEXT.heights_map.GetValue(vector.x/GAME_CONTEXT.width, vector.y/GAME_CONTEXT.width); } if (!collision_point && vector.z <= z) { collision_point = vector.clone(); } }).onComplete(vector => { //console.log(click_position, "--->", collision_point || vector); resolve(collision_point || vector); }).start(); }); }Esto generalmente funciona y me da medidas bastante precisas, tal vez de 1 a 4 unidades del mundo real. Y tal vez podría mejorarlo encontrando el punto del rayo justo cuando su z es igual a la altura del piso.
Pero el problema principal es que obtengo valores inconsistentes cada vez que hago clic. Hago clic exactamente en el mismo lugar de la pantalla, pero la coordenada (x,y,z) cambia un poco cada vez. No me da el mismo valor.
Sospecho que esto tiene que ver con Tweening y poner una duración fija de 60 milisegundos para el viaje del rayo.
¿Alguien sabe cómo arreglar esto?