Ich mache ein 3D-Spiel, in dem ich einen Ausrufezeichen über den Points of Interest platziere.
Um herauszufinden, wo auf dem 2D-Bildschirm ich meinen Marker platzieren soll, projiziere ich manuell den 3D-Punkt, an dem sich der Marker befinden soll.
Es sieht aus wie das:
Sieht sehr gut aus. Wenn sich die Markierung außerhalb des Bildschirms befindet, schneide ich die Koordinaten einfach so ab, dass sie in den Bildschirm passen. Es sieht aus wie das:
Bisher läuft die Idee ziemlich gut. Wenn sich die interessierenden Punkte jedoch hinter der Kamera befinden, werden die resultierenden X-, Y-Koordinaten invertiert (wie positiv / negativ), und ich erhalte die Markierung so, dass sie in der gegenüberliegenden Ecke des Bildschirms angezeigt wird:
(Der projizierte und dann geklemmte Punkt ist die Spitze des Markers. Beachten Sie die Drehung des Markers nicht.)
Es ist sinnvoll, da die Koordinaten hinter dem Kegelstumpf in X und Y invertiert sind. Ich invertiere also die Koordinaten, wenn sie sich hinter der Kamera befinden. Ich weiß jedoch immer noch nicht, unter welchen Bedingungen die Koordinaten invertiert werden sollen.
So sieht mein Projektionscode derzeit aus (in C # mit 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);
}
Wie Sie sehen können, besteht meine aktuelle Idee darin, die Koordinaten zu invertieren, wenn entweder die Z- oder die W-Koordinaten negativ sind. Es funktioniert meistens, aber es gibt immer noch einige sehr spezifische Kamerastandorte, an denen es nicht funktioniert. Insbesondere zeigt dieser Punkt, dass eine Koordinate arbeitet und die andere nicht (die richtige Position sollte unten rechts sein):
Ich habe versucht umzukehren, wenn:
Z
ist negativ (das macht für mich am meisten Sinn)W
ist negativ (ich verstehe die Bedeutung eines negativen W-Wertes nicht)- Entweder
Z
oderW
ist negativ (was derzeit die meiste Zeit funktioniert) Z
undW
haben ein anderes Vorzeichen, auch bekannt als:Z / W < 0
(macht für mich Sinn. funktioniert aber nicht)
Aber ich habe immer noch keinen konsistenten Weg gefunden, mit dem alle meine Punkte korrekt projiziert werden.
Irgendwelche Ideen?
quelle
AB
konvertiere ich beim Berechnen nicht die Zielposition von Weltkoordinaten in Kamerakoordinaten?Angesichts der drei Vektoren
[camera position]
,[camera direction]
und[object position]
. Berechnen Sie das Punktprodukt von[camera direction]
und[object position]-[camera position]
. Wenn das Ergebnis negativ ist, befindet sich das Objekt hinter der Kamera.Vorausgesetzt, ich habe Ihren Code richtig verstanden, wäre es:
quelle
Y
istPositionY + (y * Scaling)
. Ich werde es heute Abend versuchenZ
, genau zu0
sein, sollte sehr gering sein, die meisten Spieler werden es nie erleben, und die Auswirkungen auf das Gameplay sind in den erwarteten wenigen Fällen ein vernachlässigbarer visueller Einzelbildfehler. Ich würde sagen, Ihre Zeit wird besser woanders verbracht.Nur testen (projiziert.W <0), nicht (Z <0 || W <0).
In einigen Clip-Space-Formulierungen ( Husten OpenGL- Husten ) umfasst der sichtbare Bereich positive und negative Z-Werte, während W vor der Kamera immer positiv und hinter der Kamera negativ ist.
quelle
Und entfernen Sie diesen Teil
quelle
Versuchen Sie es mit einer Werbetafel, auf der das Bild automatisch zur Kamera zeigt und das Bild automatisch an der richtigen Stelle auf den Bildschirm gezeichnet wird
quelle