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?
sumber
AB
, apakah saya tidak mengubah posisi target dari koordinat dunia ke koordinat kamera?Diberikan tiga vektor
[camera position]
,[camera direction]
dan[object position]
. Hitung produk titik dari[camera direction]
dan[object position]-[camera position]
. Jika hasilnya negatif, objek berada di belakang kamera.Mengingat saya memahami kode Anda dengan benar, itu akan menjadi:
sumber
Y
adalahPositionY + (y * Scaling)
. Saya akan mencobanya malam iniZ
menjadi persis0
harus sangat kecil, sebagian besar pemain tidak akan pernah mengalaminya, dan dampak gameplay dalam beberapa kasus yang diharapkan adalah kesalahan visual bingkai tunggal diabaikan. Saya akan mengatakan waktu Anda lebih baik dihabiskan di tempat lain.Tes saja (diproyeksikan.W <0), bukan (Z <0 || W <0).
Dalam beberapa formulasi ruang klip ( batuk OpenGL batuk ), kisaran terlihat termasuk nilai Z positif dan negatif, sedangkan W selalu positif di depan kamera dan di belakang negatif.
sumber
Dan hapus bagian ini
sumber
Coba papan reklame, yang secara otomatis akan membuat gambar menghadap kamera, dan secara otomatis akan menggambar gambar di layar di lokasi yang tepat
sumber