Spazio dello schermo allo spazio del mondo


10

Sto scrivendo un gioco 2D in cui il mio mondo di gioco ha l' asse x da sinistra a destra, l' asse y dall'alto verso il basso e l' asse z fuori dallo schermo:

inserisci qui la descrizione dell'immagine

Mentre il mio mondo di gioco è top-down, il gioco è reso con una leggera inclinazione:

inserisci qui la descrizione dell'immagine

Sto lavorando alla proiezione dallo spazio del mondo allo spazio dello schermo e viceversa. Ho il primo a lavorare come segue:

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

Il NegateY()metodo di estensione fa esattamente quello che sembra, poiché l' asse y di XNA scorre dal basso verso l'alto invece che dall'alto verso il basso. Lo screenshot sopra mostra che tutto funziona. Fondamentalmente, ho un sacco di punti nello spazio 3D che poi rendering nello spazio dello schermo. Posso modificare le proprietà della telecamera in tempo reale e vederlo animare nella nuova posizione. Ovviamente il mio gioco reale utilizzerà gli sprite anziché i punti e la posizione della telecamera sarà fissata, ma sto solo cercando di mettere a posto tutta la matematica prima di arrivare a quello.

Ora sto provando a riconvertirmi dall'altra parte. Cioè, dato un x ed y punto nello spazio schermata sopra, determinare il punto corrispondente nello spazio globale. Quindi, se punto il cursore, diciamo, in basso a sinistra del trapezio verde, voglio ottenere una lettura dello spazio mondiale di (0, 480). La coordinata z è irrilevante. O meglio, la coordinata z sarà sempre zero quando si esegue il mapping allo spazio mondiale. In sostanza, voglio implementare questa firma del metodo:

public Vector2 ScreenPointToWorld(Vector2 point)

Ho provato diverse cose per farlo funzionare, ma non ho avuto fortuna. Il mio ultimo pensiero è che ho bisogno di chiamare Viewport.Unprojectdue volte con valori z vicini / lontani diversi , calcolare il risultante Ray, normalizzarlo, quindi calcolare l'intersezione di Raycon un Planeche rappresenta fondamentalmente il livello del suolo del mio mondo. Tuttavia, mi sono bloccato sull'ultimo passo e non ero sicuro di complicare troppo le cose.

Qualcuno può indicarmi la giusta direzione su come raggiungere questo obiettivo?

Risposte:


4

Penso che la tua idea sia praticamente perfetta! Prima calcola un raggio per il tuo cursore usando sia il piano vicino che il piano lontano come valori Z per le tue coordinate 2D (cioè usa 0 e 1 per la tua coordinata Z). Ecco un metodo di supporto per gestirlo:

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));
}

Successivamente dovrai avere Planeun'istanza che corrisponda al tuo terreno. Il modo più semplice per calcolarlo è usare il costruttore che prende tre punti sul piano e passandogli tre vertici dall'oggetto terra. Esempio di come calcolare il piano terra:

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

E infine trova il punto di intersezione tra il raggio e il piano usando questo metodo . È possibile utilizzare il parametro del risultato di uscita per calcolare le coordinate dell'intersezione come nell'esempio seguente:

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

Potrebbe essere necessario fare qualcosa anche per il NegateYmetodo, ma non sono sicuro di dove.


Questo è molto utile - grazie mille. Era l'ultima riga che mi mancava. Non riuscivo a capire cosa fare del galleggiante una volta che l'ho avuto! Penso che dovrò avere il tuo nome nei titoli di gioco :)
io--

@ user13414 In effetti, la documentazione è un po 'scarsa su quel metodo e non fornisce alcun esempio di come utilizzare la distanza per tornare al punto di intersezione.
David Gouveia,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.