Pregunta

Estoy construyendo un juego de juntas en WebGL. La placa se puede girar/acercarse. Necesito una forma de traducir un clic en el elemento de lona (x, y) al punto relevante en el espacio 3D (x, y, z). El resultado final es que quiero saber la coordenada (x, y, z) que contiene el punto que toca el objeto más cercano al usuario. Por ejemplo, el usuario hace clic en una pieza, y te imaginas un rayo que viaja a través del espacio 3D que pasa por la pieza y el tablero de juego, pero quiero la coordina (X, Y, Z) de la pieza en el punto donde estaba tocado.

Siento que este debe ser un problema muy común, pero parece que no puedo encontrar una solución en mis Googles. Debe haber alguna forma de proyectar la vista actual del espacio 3D en 2D para que pueda mapear cada punto en el espacio 2D hasta el punto relevante en el espacio 3D. Quiero que el usuario pueda mousar sobre un espacio en el tablero y hacer que el punto cambie de color.

¿Fue útil?

Solución

Estás buscando una función improvisada, que convierte las coordenadas de pantalla en un rayo fundido desde la posición de la cámara en el mundo 3D. Luego debe realizar pruebas de intersección de rayos/triángulos para encontrar el triángulo más cercano a la cámara que también se cruza con el rayo.

Tengo un ejemplo de improvisación disponible en Jax/Camera.js#L568 - Pero aún necesitará implementar la intersección de rayos/triángulos. Tengo una implementación de eso en jax/triangle.js#l113.

Sin embargo, hay una alternativa más simple y (generalmente) más rápida llamada 'selección'. Use esto si desea seleccionar un objeto completo (por ejemplo, una pieza de ajedrez), y si no le importa dónde hizo clic el mouse. La forma de WebGL de hacerlo es representar toda la escena en varios tonos de azul (el azul es una clave, mientras que el rojo y el verde se usan para identificaciones únicas de los objetos en la escena) a una textura, luego lea un píxel desde esa textura. La decodificación del RGB en la ID del objeto le dará el objeto que se hizo clic. Nuevamente, he implementado esto y está disponible en jax/world.js#l82. (Ver también líneas 146, 162, 175.)

Ambos enfoques tienen pros y contras (discutidos aquí Y en algunos de los comentarios posteriores) y deberá averiguar qué enfoque satisface mejor sus necesidades. La selección es más lenta con escenas enormes, pero la improvisación en JS puro es extremadamente lento (ya que JS en sí mismo no es tan rápido), por lo que mi mejor recomendación sería experimentar con ambos.

Para su información, también puede ver el proyecto GLU y el código Un improyect, en el que basé mi código libremente: http://www.opengl.org/wiki/GlUproject_and_guunproject_code

Otros consejos

Estoy trabajando en este problema en este momento: el enfoque que estoy tomando es

  1. Renderizar objetos para elegir el buffer cada uno con un color único
  2. Lea el píxel de búfer, mapa al objeto seleccionado
  3. Render el objeto seleccionado a buffer con cada color de píxeles una función de z-deph
  4. Lea el píxel de búfer, mapa de nuevo a Z-Depth
  5. Hemos elegido objeto y aproximado Z para las coords de selección

Esta es la demostración de trabajo

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/

culto de uno de los hilos. No estoy seguro de (x, y, z) pero puedes obtener el 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};
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top