Saya membuat game 3D di mana saya menempatkan tanda seru di atas tempat menarik.
Untuk mengetahui di mana di layar 2D saya harus meletakkan penanda saya, saya secara manual memproyeksikan titik 3D di mana penanda itu berada.
Ini terlihat seperti ini:
Terlihat bagus. Ketika penanda berada di luar layar, saya cukup klip koordinat sehingga mereka masuk ke layar. Ini terlihat seperti ini:
Sejauh ini idenya berjalan cukup baik. Namun, ketika tempat menarik berada di belakang kamera, koordinat X, Y yang dihasilkan dibalik (seperti dalam positif / negatif), dan saya mendapatkan penanda untuk muncul di sudut berlawanan dari layar, seperti ini:
(Titik yang diproyeksikan-kemudian-dijepit adalah ujung marker. Jangan pedulikan rotasi marker)
Masuk akal, karena koordinat di belakang frustum terbalik dalam X dan Y. Jadi yang saya lakukan adalah membalikkan koordinat ketika mereka berada di belakang kamera. Namun, saya masih tidak tahu persis kondisi kapan koordinat harus dibalik.
Saat ini seperti apa kode proyeksi saya (dalam C # dengan 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);
}
Seperti yang Anda lihat, ide saya saat ini adalah membalikkan koordinat ketika koordinat Z atau W negatif. Ini berfungsi - hampir - sebagian besar waktu, tetapi masih ada beberapa lokasi kamera yang sangat spesifik di mana ia tidak bekerja. Secara khusus, titik ini menunjukkan satu koordinat berfungsi dan yang lainnya tidak (lokasi yang benar adalah kanan bawah):
Saya telah mencoba membalikkan ketika:
Z
negatif (ini yang paling masuk akal bagi saya)W
negatif (saya tidak mengerti arti dari nilai W negatif)- Baik
Z
atauW
negatif (apa yang saat ini paling sering bekerja) Z
danW
dari tanda yang berbeda, alias:Z / W < 0
(masuk akal bagi saya. tidak bekerja sekalipun)
Tetapi masih belum menemukan cara yang konsisten dengan semua poin saya diproyeksikan dengan benar.
Ada ide?