Pantalla espacio al espacio mundial

10

Estoy escribiendo un juego 2D en el que mi mundo de juego tiene eje x de izquierda a derecha, eje y de arriba a abajo y eje z fuera de la pantalla:

ingrese la descripción de la imagen aquí

Mientras mi mundo de juego es de arriba hacia abajo, el juego se presenta con una ligera inclinación:

ingrese la descripción de la imagen aquí

Estoy trabajando en proyectar del espacio mundial al espacio de la pantalla, y viceversa. Tengo el primero trabajando de la siguiente manera:

var viewport = new Viewport(0, 0, this.ScreenWidth, this.ScreenHeight);
var screenPoint = viewport.Project(worldPoint.NegateY(), this.ProjectionMatrix, this.ViewMatrix, this.WorldMatrix);

El NegateY()método de extensión hace exactamente lo que parece, ya que el eje y de XNA se ejecuta de abajo hacia arriba en lugar de arriba hacia abajo. La captura de pantalla anterior muestra que todo esto funciona. Básicamente, tengo un montón de puntos en el espacio 3D que luego renderizo en el espacio de la pantalla. Puedo modificar las propiedades de la cámara en tiempo real y verlo animado a la nueva posición. Obviamente mi juego real usará sprites en lugar de puntos y la posición de la cámara será fija, pero solo estoy tratando de poner todas las matemáticas en su lugar antes de llegar a eso.

Ahora, estoy tratando de volver a convertir a la inversa. Es decir, dado un punto x e y en el espacio de la pantalla anterior, determine el punto correspondiente en el espacio mundial. Entonces, si apunto el cursor a, digamos, la parte inferior izquierda del trapecio verde, quiero obtener una lectura del espacio mundial de (0, 480). La coordenada z es irrelevante. O, más bien, la coordenada z siempre será cero al mapear de nuevo al espacio mundial. Esencialmente, quiero implementar la firma de este método:

public Vector2 ScreenPointToWorld(Vector2 point)

He intentado varias cosas para que esto funcione, pero no tengo suerte. Mi último pensamiento es que necesito llamar Viewport.Unprojectdos veces con diferentes valores z cercanos / lejanos , calcular la resultante Ray, normalizarla, luego calcular la intersección de la Raycon una Planeque básicamente representa el nivel del suelo de mi mundo. Sin embargo, me quedé atrapado en el último paso y no estaba seguro de si estaba complicando demasiado las cosas.

¿Alguien puede señalarme en la dirección correcta sobre cómo lograr esto?

yo--
fuente

Respuestas:

4

¡Creo que tu idea es bastante acertada! Primero calcule un rayo para su cursor usando tanto el plano cercano como el plano lejano como valores Z para sus coordenadas 2D (es decir, use 0 y 1 para su coordenada Z). Aquí hay un método auxiliar para manejar eso:

public Ray GetScreenRay(Vector2 screenPosition, Viewport viewport, Matrix projectionMatrix, Matrix viewMatrix, Matrix worldMatrix)
{
    Vector3 nearPoint = viewport.Unproject(new Vector3(screenPosition, 0f), projectionMatrix, viewMatrix, worldMatrix);
    Vector3 farPoint = viewport.Unproject(new Vector3(screenPosition, 1f), projectionMatrix, viewMatrix, worldMatrix);
    return new Ray(nearPoint, Vector3.Normalize(farPoint - nearPoint));
}

A continuación, deberá tener una Planeinstancia que coincida con su terreno. La forma más fácil de calcularlo es usar el constructor que toma tres puntos en el plano y pasarle tres vértices desde el objeto del suelo. Ejemplo de cómo calcular el plano de tierra:

Plane groundPlane = new Plane(ground.Vertices[0], ground.Vertices[1], ground.Vertices[2]);

Y finalmente encuentre el punto de intersección entre el rayo y el plano usando este método . Puede usar el parámetro de resultado de salida para calcular las coordenadas de intersección como en el siguiente ejemplo:

float? result;
mouseRay.Intersects(ref groundPlane, out result);
if(result != null)
    Vector3 worldPoint = mouseRay.Position + mouseRay.Direction * result.Value;

Es posible que también deba hacer algo sobre el NegateYmétodo, pero no estoy seguro de dónde.

David Gouveia
fuente
Esto es súper útil, muchas gracias. Era la última línea que me faltaba. ¡No pude averiguar qué hacer con el flotador una vez que lo tuve! Creo que tendré que poner tu nombre en los créditos de mi juego :)
yo--
@ user13414 De hecho, la documentación es un poco escasa en ese método y no da ningún ejemplo de cómo usar la distancia para volver al punto de intersección.
David Gouveia