Mengapa GPU membagi ruang klip Z dengan W, untuk posisi?

8

Latar Belakang:
Saya menemukan bahwa sangat mudah untuk menggunakan buffer kedalaman linier, hanya menggunakan sedikit modifikasi pada transformasi vertex kanonik. Metode paling sederhana ditemukan di bagian bawah https://www.mvps.org/directx/articles/linear_z/linearz.htm .

Namun, peringatannya adalah itu hanya bekerja untuk segitiga yang tidak perlu terpotong dengan pesawat dekat atau jauh. (Dan solusi alternatif, melakukan pembagian perspektif dalam vertex shader, akan menghasilkan masalah yang sama untuk empat pesawat frustum lainnya.)

Karena kliping memerlukan interpolasi linier untuk bekerja di keempat koordinat ruang klip, saya pikir tidak mungkin untuk bekerja dengan kedalaman linier, hanya menggunakan vertex shader. Tetapi alasan untuk itu adalah semua Z dibagi oleh W.

Mengapa itu dilakukan? X dan Y perlu dibagi berdasarkan jarak dari kamera, tetapi koordinat Z tidak, cocok dengan sempurna ke dalam kotak NDC.

Jessy
sumber

Jawaban:

13

Jika Anda melakukan gambar perspektif dan model Anda memiliki persimpangan implisit maka, jika Anda menggunakan "linear Z", persimpangan tersebut akan muncul di tempat yang salah.

Sebagai contoh, pertimbangkan pesawat darat sederhana dengan garis kutub telepon, mundur ke kejauhan, yang menembus tanah (dan terus di bawah). Persimpangan implisit akan ditentukan oleh nilai kedalaman interpolasi. Jika itu tidak diinterpolasi dengan 1/Z, maka ketika simpul yang diproyeksikan telah dihitung dengan perspektif, gambar akan terlihat salah.

Saya minta maaf untuk kualitas non-estetika dari ilustrasi berikut tetapi saya melakukannya pada tahun '97.

Gambar pertama menunjukkan efek rendering yang diperlukan. (Perhatikan bahwa "tiang" biru pergi cukup jauh di bawah bidang tanah sehingga terpotong di bagian bawah gambar)

masukkan deskripsi gambar di sini

Gambar kedua ini menunjukkan hasil menggunakan buffer kedalaman non-resiprokal: (Permintaan maaf untuk perubahan skala - ini disalin dari dokumen MS Word lama dan saya tidak tahu apa yang terjadi dengan penskalaan.)

masukkan deskripsi gambar di sini

Seperti yang Anda lihat, hasilnya salah.

Pada catatan lain, apakah Anda benar - benar menginginkan representasi Z linier? Jika Anda memberikan perspektif, tentu seseorang ingin lebih presisi lebih dekat ke kamera daripada di kejauhan?

Re komentar Anda nanti:

"Jika itu tidak diinterpolasi dengan 1 / Z" itu saya tidak mengerti. Interpolasi apa itu?

Hal pertama yang perlu diperhatikan adalah bahwa, dengan proyeksi perspektif standar, garis lurus di ruang dunia tetap garis lurus di ruang perspektif. Jarak / panjang, bagaimanapun, tidak dipertahankan.

Untuk kesederhanaan, mari kita asumsikan transformasi perspektif sepele digunakan untuk memproyeksikan simpul, yaitu

XScreen=XWHairldZWHairld
YScreen=YWHairldZWHairld
Kita juga harus menghitung kedalaman ruang-layar timbal balik, misalnya
ZScreen=1ZWHairld
tetapi linear Z di buffer kedalaman akan, bagi saya, memerlukan sesuatu seperti:
ZScreen=scSebuahleZWHairld
(Kita dapat mengasumsikan di sini bahwa skala = 1)

Mari kita asumsikan kita memiliki garis dengan titik akhir ruang angkasa dunia

[001]Sebuahnd[200010]
Dengan perspektif memetakan peta ini untuk menyaring koordinat ruang
[001]Sebuahnd[2000,1]

Sistem render / perangkat keras akan menginterpolasi ruang layar z secara linier, jadi pada titik 1/2 arah garis, seperti yang muncul di layar, yaitu pada piksel (10, 0), kita akan mendapatkan proyeksi (terbalik) Z nilai 0,55, yang sesuai dengan nilai ruang dunia Z nilai ~ 1,818. Mengingat nilai Z awal dan akhir, ini adalah sekitar 20% sepanjang garis.

Jika sebaliknya, kami mencoba interpolasi menggunakan nilai Z asli, kami akan berakhir dengan Z yang sesuai dengan nilai ruang dunia 5.5. Selama tidak ada yang berpotongan, Anda mungkin baik-baik saja (saya belum memikirkannya dengan saksama) tetapi apa pun dengan persimpangan implisit akan salah.

Apa yang saya tidak sebutkan adalah bahwa sekali Anda memperkenalkan perspektif benar texturing (atau bahkan perspektif benar shading), Anda harus melakukan interpolasi pixel per 1 / w dan, selain itu, juga menghitung, per pixel, kebalikan dari nilai interpolasi tersebut.

Simon F
sumber
Saya rasa saya tidak akan bisa memahami jawaban ini tanpa lebih banyak matematika / diagram. Dan ya, lebih presisi, lebih dekat, mungkin masuk akal, tetapi penskalaan dari linear oleh far / z, yang merupakan standar, tidak masuk akal. Ini menghasilkan buffer kedalaman yang menjadi lebih linier semakin dekat dua pesawat klip satu sama lain. Tampaknya seperti penggabungan dua konsep: layar ruang-linier Z, dan pemetaan buffer kedalaman yang tidak konstan untuk peretasan kinerja.
Jessy
Secara khusus, itu adalah, "jika mereka tidak diinterpolasi dengan 1 / Z" yang saya tidak mengerti. Interpolasi apa itu?
Jessy
1
Saya akan menambahkan beberapa teks tambahan untuk mudah-mudahan menjelaskan
Simon F
Terima kasih! Saya pikir masalahnya adalah "Sistem rendering / perangkat keras akan menginterpolasi ruang layar secara z". Saya mendapat kesan bahwa posisi NDC akan dihitung sebagai (x, y, z) / wper-fragmen, tetapi tampaknya, alih-alih, kita harus berurusan dengan versi interpolasi linear dari (x/w, y/w, z/w)? Itu tampaknya tidak masuk akal bagi saya pada tahun 2018, tetapi akan lebih baik untuk mengetahui jika itu adalah hack yang harus kita jalani sekarang juga!
Jessy
Untuk melakukan perspektif yang benar texturing / shading / apa pun, Anda perlu interpolasi linear (Val / w) nilai, dan kemudian, per fragmen, lakukan pembagian dengan 1 / w interpolasi linear. Agak sulit dijelaskan hanya dalam komentar, tetapi ada sedikit penjelasan di computergraphics.stackexchange.com/a/4799/209 . Atau, lakukan pencarian untuk artikel Jim Blinn "Interpolasi Hiperbolik"
Simon F
6

Menggunakan Z / W untuk buffer kedalaman berjalan lebih dalam daripada hanya menempel pada pesawat dekat dan jauh. Seperti Simon singgung, ini ada hubungannya dengan interpolasi antara simpul-simpul segitiga, selama rasterisasi.

Z / W adalah opsi unik yang memungkinkan nilai kedalaman NDC dihitung dengan benar untuk titik-titik di bagian dalam segitiga, dengan secara sederhana menginterpolasi nilai kedalaman NDC dari simpul, di ruang layar . Pada prinsipnya, kita bisa menggunakan fungsi apa pun yang kita suka untuk memetakan ruang kamera Z ke nilai buffer kedalaman — tetapi pilihan lain selain Z / W akan membutuhkan matematika yang lebih rumit untuk dilakukan per piksel, yang akan lebih lambat, dan lebih sulit untuk membangun perangkat keras.

Perhatikan bahwa jika Anda menggunakan buffer kedalaman linier, maka tentu saja nilai kedalaman interpolasi linier akan benar di ruang dunia ... tetapi tidak, secara umum, di ruang layar! Dan itu adalah ruang layar yang penting untuk rasterisasi, karena kita harus dapat menghasilkan nilai kedalaman perspektif-benar (dan nilai atribut lainnya, seperti UV) untuk setiap pusat piksel, atau titik sampel lainnya, dalam batas-batas ruang layar dari suatu segitiga dirasterisasi.

Nathan Reed
sumber
Saya tidak tahu bagaimana mendesain GPU, tetapi bagi saya sepertinya yang diperlukan hanyalah interpolasi Z, bukan Z / W, untuk kedalaman linier, dan interpolasi Z / W masih bisa terjadi setelah itu untuk apa pun yang terlihat. Saya masih tidak tahu apakah ini masalah alasan yang baik atau salah satu dari "tidak ada yang peduli sehingga kami tidak repot-repot memperbarui".
Jessy
Interpolasi Z bukannya Z / W tidak memberikan hasil yang benar dalam ruang layar. Z / W tidak.
Nathan Reed
Baik. Tetapi jika buffer kedalaman dikuantifikasi dengan presisi yang lebih rendah daripada posisi, maka, selain menjadi performan ketika bekerja, itu bukan ide yang baik untuk menyimpan potongan skala ruang layar Z. Jika interpolasi linier adalah semua yang kita dapatkan, maka memotong kebutuhan terjadi di ruang tampilan. Dan Z perlu diinterpolasi sebelum pembagian oleh W, untuk buffer kedalaman, dan setelahnya, untuk apa yang telah Anda lakukan. Jadi apakah jawaban untuk pertanyaan saya, "karena GPU selalu hanya diinterpolasi dalam ruang klip karena itu adalah satu-satunya solusi praktis pada GPU pertama, dan itu telah bekerja dengan cukup baik sejak itu"?
Jessy
Saya tidak mengikuti apa yang Anda maksud tentang "dikuantisasi ke presisi yang lebih rendah dari posisi", atau "menyimpan potongan skala ruang layar Z".
Nathan Reed
1
Juga, "Z perlu diinterpolasi sebelum pembagian oleh W, untuk buffer kedalaman" —tidak. Itulah yang saya coba jelaskan. Anda mendapatkan jawaban yang salah jika Anda menyisipkan Z (atau apa pun) di ruang layar tanpa membaginya dengan W terlebih dahulu. Anda tampaknya terjebak pada gagasan ini bahwa buffer Z linier hanya akan berfungsi jika kita tidak membaginya dengan W. Tetapi itu tidak akan berhasil — itu tidak akan diinterpolasi dalam ruang layar dengan benar.
Nathan Reed