Adegan OpenGL saya memiliki objek yang diposisikan pada jarak yang sangat jauh dari asalnya. Ketika saya melihat objek-objek ini, dan menggeser / memutar / memperbesar kamera di sekitar mereka, mereka 'jitter'. Yaitu, simpul-simpul yang terdiri dari objek-objek itu seolah-olah membentur sebuah kotak 3d poin imajiner. Saya sudah membaca ini adalah masalah umum karena jumlah informasi yang dapat disimpan menggunakan presisi floating point (yang OpenGL, dan cukup banyak hal lain gunakan). Saya tidak mengerti mengapa ini terjadi.
Saat mencari solusi, saya menemukan perbaikan 'asal mengambang' yang sangat sederhana, dan sepertinya berhasil. Saya hanya mengubah segalanya sehingga objek saya berada pada posisi relatif yang sama tetapi apa pun yang dilihat kamera saya dekat dengan aslinya. Saya menemukan penjelasan di sini: http://floatingorigin.com/ , tetapi saya tidak bisa mengikutinya.
Jadi ... Bisakah seseorang menjelaskan mengapa memposisikan adegan saya sangat jauh (katakanlah 10 juta unit) dari hasil asal dalam perilaku tidak menentu yang saya amati? Dan juga mengapa pindah dekat dengan asal memperbaiki masalah?
Jawaban:
Ini SEMUA karena cara floating point direpresentasikan dalam komputer.
Integer disimpan secara langsung; setiap unit persis "satu" terpisah dari "sebelumnya" seperti yang Anda harapkan dengan angka yang dapat dihitung.
Dengan angka floating point ini tidak persis demikian. Sebagai gantinya, beberapa bit mengindikasikan EXPONENT, dan sisanya menunjukkan apa yang dikenal sebagai mantissa , atau bagian fraksional yang kemudian DIBAGAI oleh bagian eksponen (secara implisit 2 ^ exp) untuk memberikan hasil akhir.
Lihat di sini untuk penjelasan visual bit.
Justru karena eksponen ini menjadi bagian aktual dari bit-bit itu presisi mulai WANE begitu angka tumbuh lebih besar.
Untuk melihat ini dalam tindakan, mari kita lakukan representasi titik mengambang-faux tanpa masuk ke seluk-beluk: ambil eksponen kecil seperti 2 dan lakukan beberapa bagian fraksional untuk menguji:
2 * 2 ^ 2 = 8
3 * 2 ^ 2 = 12
4 * 2 ^ 2 = 16
... dll.
Angka-angka ini tidak tumbuh sangat jauh hanya pada eksponen 2. Tapi sekarang mari kita coba eksponen 38:
2 * 2 ^ 38 = 549755813888
3 * 2 ^ 38 = 824633720832
4 * 2 ^ 38 = 1099511627776
Wah, perbedaan besar sekarang!
Contohnya, walaupun tidak secara khusus pergi ke COUNTABLE SANGAT BERIKUTNYA (itu akan menjadi bagian fraksional berikutnya tergantung pada berapa banyak bit itu), ada di sana untuk menunjukkan kehilangan presisi setelah angka tumbuh lebih besar. Unit "selanjutnya yang dapat dihitung" dalam mengapung sangat kecil dengan eksponen kecil dan SANGAT besar dengan eksponen lebih besar, sedangkan dalam bilangan bulat SELALU 1.
Alasan metode asal float bekerja adalah karena itu scaling semua angka-angka floating-eksponen berpotensi besar ini BAWAH ke eksponen kecil sehingga "countables berikutnya" (presisi) bisa sangat kecil dan bahagia.
sumber
Karena angka floating point direpresentasikan sebagai fraksi + eksponen + tanda, dan Anda hanya memiliki jumlah bit yang tetap untuk bagian fraksi.
http://en.wikipedia.org/wiki/Single_precision
Ketika Anda mendapatkan angka yang lebih besar dan lebih besar, Anda tidak memiliki bit untuk mewakili bagian yang lebih kecil.
sumber
Klasik di lapangan harus diangkat: Apa yang harus diketahui setiap ilmuwan komputer tentang angka floating point .
Tetapi intinya berkaitan dengan bagaimana bilangan floating point presisi tunggal (ganda) hanya bilangan biner 32 bit (64-bit) dengan 1 bit mewakili tanda, eksponen 8-bit (11-bit) dari basis 2 , dan 23bit (52-bit) secara signifikan (tanda kurung adalah nilai untuk ganda).
Itu berarti angka positif terkecil yang dapat Anda wakili dalam presisi tunggal adalah 0,0000000000000000000001 x 2 -127 = 2 -22 x 2 -127 = 2 -149 ~ 1,40 x 10 -45 .
Angka positif berikutnya adalah dua kali lipat yaitu: 0,000000000000000000000010 x 2 -127 = 2 -148 ~ 2,80 x 10 -45 , dan kemudian angka berikutnya adalah jumlah dari dua sebelumnya 0,0000000000000000000000000000000000000000000000000000 x00 -127 = 3 x 2 -149 ~ 4.2 - 45 .
Ini terus meningkat dengan perbedaan konstan yang sama hingga: 0,111111111111111111111111 x 2 -127 = 2 -126 - 2 149 ~ 1,17549435 x 10 -38 - 0,00000014 x 10 -38 = 1,17549421 x 10 -38
Sekarang Anda telah mencapai angka normal (di mana angka pertama dalam signifikans adalah 1) khususnya: 1,000000000000000000000000 x 2 -126 = 2 -126 = 1,17549435 x 10 -38 dan angka berikutnya adalah 1,000000000000000000000001 x 2 -126 = 2 -126 (1 + 2 -22 ) = 1.17549435 x 1.00000023.
sumber
Alasan mengapa angka titik-mengambang menjadi kurang tepat lebih jauh dari titik asal adalah karena angka titik-mengambang seharusnya mampu mewakili angka besar. Cara ini dilakukan meminjamkannya istilah "floating point". Ia membagi nilai-nilai yang mungkin dapat diambilnya (yang ditentukan oleh panjang bitnya) sehingga ada kira-kira angka yang sama untuk setiap eksponen: Untuk float 32-bit, 23 bit menentukan mantissa atau signifikansi. Jadi itu akan dapat mengambil nilai 2 ^ 23 nilai yang berbeda di setiap rentang eksponen. Salah satu rentang eksponen ini adalah 1-2 [2 ^ 0 hingga 2 ^ 1], jadi memisahkan rentang 1 ke 2 menjadi 2 ^ 23 nilai yang berbeda memungkinkan banyak presisi.
Tetapi memisahkan rentang [2 ^ 10 ke 2 ^ 11] menjadi 2 ^ 23 nilai yang berbeda berarti ruang antara masing-masing nilai jauh lebih besar. Jika tidak, maka 23 bit tidak akan cukup. Semuanya adalah kompromi: Anda membutuhkan jumlah bit yang tak terbatas untuk mewakili bilangan real. Jika aplikasi Anda bekerja dengan cara yang memungkinkan Anda lolos dengan presisi yang lebih rendah untuk nilai yang lebih besar, dan Anda mendapat manfaat karena dapat benar - benar mewakili nilai-nilai besar , Anda menggunakan representasi floating point.
sumber
Mungkin agak sulit untuk menawarkan contoh spesifik tentang bagaimana presisi floating-point bekerja. Untuk melengkapi jawaban lain, inilah satu. Katakanlah kita memiliki angka floating-point desimal , dengan tiga digit mantissa dan satu digit eksponen:
Ketika eksponen adalah 0, setiap bilangan bulat dalam kisaran 0–999 dapat direpresentasikan secara tepat. Saat 1, Anda pada dasarnya mengalikan setiap elemen dari rentang itu dengan 10, sehingga Anda mendapatkan rentang 0–9990; tetapi sekarang, hanya kelipatan 10 yang dapat direpresentasikan secara akurat, karena Anda masih memiliki presisi tiga digit. Ketika eksponen berada pada maksimum 9, perbedaan antara setiap pasangan bilangan bulat yang diwakili adalah satu miliar . Anda benar-benar memperdagangkan presisi untuk kisaran.
Ini bekerja dengan cara yang sama dengan angka-angka titik-mengambang biner: setiap kali eksponen naik satu, rentangnya berlipat ganda , tetapi jumlah nilai yang dapat diwakili dalam rentang itu dikurangi setengahnya . Ini berlaku untuk bilangan pecahan juga, yang tentu saja merupakan sumber masalah Anda.
sumber
Secara umum, resolusi semakin buruk karena resolusi dikalikan dengan nilai eksponen (2 ** bagian eksponen).
sebagai pengakuan atas komentar josh: yang di atas hanya untuk menempatkan jawabannya dalam pernyataan singkat. Tentu saja, seperti yang telah saya coba tunjukkan pada http://floatingorigin.com/ , ini baru akan dimulai menuju solusi keseluruhan dan program Anda dapat memiliki jitter dari sejumlah tempat: dalam pipa presisi atau bagian lain dari kode .
sumber
Buffer kedalaman OpenGL tidak linier . Semakin jauh Anda pergi, semakin buruk resolusi yang dimilikinya. Saya sarankan untuk membaca ini . Sesuatu diambil dari sana (12.070):
Dan satu lagi (12.040):
Jadi, Anda harus memindahkan pesawat kliping terdekat Anda sejauh mungkin dan pesawat jauh Anda terdekat yang Anda bisa.
sumber