Sto realizzando un gioco 3D in cui metto un punto esclamativo sopra i punti di interesse.
Per scoprire dove dovrei posizionare il mio marker nella schermata 2D, sto proiettando manualmente il punto 3D dove dovrebbe essere il marker.
Sembra così:
Sembra abbastanza buono Quando il marker si trova fuori dallo schermo, ho semplicemente ritagliato le coordinate in modo che si adattino allo schermo. Sembra così:
Finora l'idea sta andando abbastanza bene. Tuttavia, quando i punti di interesse sono dietro la telecamera, le coordinate X, Y risultanti vengono invertite (come in positivo / negativo) e ottengo l'indicatore per apparire nell'angolo opposto dello schermo, in questo modo:
(Il punto proiettato, quindi bloccato, è la punta del marker. Non importa la rotazione del marker)
Ha senso, dal momento che le coordinate dietro il frustum sono invertite in X e Y. Quindi quello che sto facendo è invertire le coordinate quando sono dietro la telecamera. Tuttavia, non so ancora quale sia esattamente la condizione in cui le coordinate dovrebbero essere invertite.
Questo è attualmente l'aspetto del mio codice di proiezione (in C # con SharpDX):
public override PointF ProjectPosition(float viewportWidth, float viewportHeight, float y)
{
var projectionMatrix = Matrix.PerspectiveFovRH(GetCalibratedFOV(Camera.FOV, viewportWidth, viewportHeight), viewportWidth / viewportHeight, Camera.Near, Camera.Far);
var viewMatrix = Matrix.LookAtRH(new Vector3(Camera.PositionX, Camera.PositionY, Camera.PositionZ), new Vector3(Camera.LookAtX, Camera.LookAtY, Camera.LookAtZ), Vector3.UnitY);
var worldMatrix = Matrix.RotationY(Rotation) * Matrix.Scaling(Scaling) * Matrix.Translation(PositionX, PositionY, PositionZ);
var worldViewProjectionMatrix = worldMatrix * viewMatrix * projectionMatrix;
Vector4 targetVector = new Vector4(0, y, 0, 1);
Vector4 projectedVector = Vector4.Transform(targetVector, worldViewProjectionMatrix);
float screenX = (((projectedVector.X / projectedVector.W) + 1.0f) / 2.0f) * viewportWidth;
float screenY = ((1.0f - (projectedVector.Y / projectedVector.W)) / 2.0f) * viewportHeight;
float screenZ = projectedVector.Z / projectedVector.W;
// Invert X and Y when behind the camera
if (projectedVector.Z < 0 ||
projectedVector.W < 0)
{
screenX = -screenX;
screenY = -screenY;
}
return new PointF(screenX, screenY);
}
Come puoi vedere, la mia idea attuale è quella di invertire le coordinate quando le coordinate Z o W sono negative. Funziona la maggior parte delle volte, ma ci sono ancora alcune posizioni della telecamera molto specifiche in cui non funziona. In particolare questo punto mostra una coordinata funzionante e l'altra no (la posizione corretta dovrebbe essere in basso a destra):
Ho provato a invertire quando:
Z
è negativo (questo è ciò che ha più senso per me)W
è negativo (non capisco il significato di un valore W negativo)- Sia
Z
oW
è negativo (quello che sta attualmente lavorando la maggior parte del tempo) Z
eW
sono di segno diverso, aka:Z / W < 0
(ha senso per me. non funziona però)
Ma non ho ancora trovato un modo coerente con cui proiettare correttamente tutti i miei punti.
Qualche idea?