Layar ruang ke ruang dunia

10

Saya menulis permainan 2D di mana dunia permainan saya memiliki sumbu x yang berjalan dari kiri ke kanan, sumbu y berjalan dari atas ke bawah, dan sumbu z keluar dari layar:

masukkan deskripsi gambar di sini

Sementara dunia gim saya top-down, gim ini sedikit miring:

masukkan deskripsi gambar di sini

Saya sedang mengerjakan proyeksi dari ruang dunia ke ruang layar, dan sebaliknya. Saya memiliki mantan bekerja sebagai berikut:

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

The NegateY()metode penyuluhan tidak persis apa yang terdengar seperti, karena XNA ini y sumbu berjalan bawah ke atas, bukan atas ke bawah. Tangkapan layar di atas menunjukkan ini berfungsi semua. Pada dasarnya, saya memiliki banyak titik dalam ruang 3D yang kemudian saya render dalam ruang layar. Saya dapat memodifikasi properti kamera secara real time dan melihatnya hidup dengan posisi baru. Jelas permainan saya yang sebenarnya akan menggunakan sprite daripada poin dan posisi kamera akan diperbaiki, tapi saya hanya mencoba untuk mendapatkan semua matematika di tempatnya sebelum sampai ke sana.

Sekarang, saya mencoba untuk mengkonversi kembali ke arah lain. Artinya, diberi titik x dan y di ruang layar di atas, tentukan titik yang sesuai di ruang dunia. Jadi jika saya arahkan kursor ke, katakanlah, kiri bawah trapesium hijau, saya ingin mendapatkan pembacaan ruang dunia dari (0, 480). The z koordinat tidak relevan. Atau, lebih tepatnya, koordinat z akan selalu nol ketika memetakan kembali ke ruang dunia. Pada dasarnya, saya ingin menerapkan metode tanda tangan ini:

public Vector2 ScreenPointToWorld(Vector2 point)

Saya sudah mencoba beberapa hal untuk membuatnya bekerja tetapi saya tidak beruntung. Pemikiran terakhir saya adalah bahwa saya perlu menelepon Viewport.Unprojectdua kali dengan nilai z dekat / jauh yang berbeda , menghitung hasilnya Ray, menormalkannya, lalu menghitung persimpangan Raydengan Planeyang pada dasarnya mewakili permukaan tanah dari dunia saya. Namun, saya terjebak pada langkah terakhir dan tidak yakin apakah saya terlalu rumit.

Adakah yang bisa mengarahkan saya ke arah yang benar tentang cara mencapai ini?

saya--
sumber

Jawaban:

4

Saya pikir ide Anda cukup tepat! Pertama-tama hitunglah sinar untuk kursor Anda menggunakan bidang dekat dan bidang jauh sebagai nilai Z untuk koordinat 2D Anda (yaitu gunakan 0 dan 1 untuk koordinat Z Anda). Inilah metode pembantu untuk mengatasinya:

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

Selanjutnya Anda harus memiliki Planeinstance yang cocok dengan tanah Anda. Cara termudah untuk menghitungnya adalah dengan menggunakan konstruktor yang mengambil tiga titik di pesawat, dan melewatkannya setiap tiga simpul dari objek tanah. Contoh cara menghitung bidang tanah:

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

Dan akhirnya menemukan titik persimpangan antara sinar dan pesawat menggunakan metode ini . Anda dapat menggunakan parameter hasil keluar untuk menghitung koordinat persimpangan seperti pada contoh di bawah ini:

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

Anda mungkin harus melakukan sesuatu tentang NegateYmetode ini juga, tetapi saya tidak yakin di mana.

David Gouveia
sumber
Ini sangat membantu - terima kasih banyak. Itu adalah baris terakhir yang saya lewatkan. Saya tidak tahu apa yang harus dilakukan dengan float begitu saya memilikinya! Saya pikir saya harus memiliki nama Anda di kredit permainan saya :)
saya
@ user13414 Memang, dokumentasi agak langka pada metode itu dan tidak memberikan contoh bagaimana menggunakan jarak untuk mendapatkan kembali titik persimpangan.
David Gouveia