Apa kegunaan radius kuadrat dan radius kuadrat terbalik untuk perhitungan pencahayaan?

16

Pada salah satu slide dari "DirectX 11 Rendering di Battlefield 3" PowerPoint saya perhatikan kode berikut:

struct Light {
    float3 pos; float sqrRadius;
    float3 color; float invSqrRadius;
}

Saya tidak mengerti mengapa mereka menyimpan jari-jari kuadrat dan bahkan kuadrat terbalik (yang saya percaya hanya jari-jari 1-kuadrat) daripada hanya menyimpan jari-jari? Bagaimana mereka menggunakan data ini dalam perhitungan mereka? Apalagi bagaimana dengan lampu kerucut dan garis? Struct ini harus hanya untuk lampu titik, saya tidak bisa melihatnya bekerja untuk jenis lain - tidak ada data yang cukup. Masih saya ingin tahu bagaimana mereka menggunakan kotak itu dan invSquare.

PEMBARUAN: Ok akhirnya saya mengerti.

Berikut ini adalah persamaan redaman cahaya klasik, yang mudah ditemukan di internet:

float3 lightVector = lightPosition - surfacePosition;

float attenuation = saturate(1 - length(lightVector)/lightRadius);

Ini relatif mahal karena length(lightVector)sebenarnya melakukan ini:

length(lightVector) = sqrt(dot(lightVector, lightVector);

Selain itu operasi divisi (/lightRadius)juga cukup mahal.

Alih-alih menghitung redaman cahaya dengan cara ini, Anda dapat menghitungnya dengan cara berikut, yang akan jauh lebih cepat:

attenuation = saturate(1 - dot(lightVector, lightVector)*invRadiusSqr);

di mana invRadiusSqr dapat dipra-komputasi pada level CPU dan dilewatkan sebagai konstanta shader.

Selain itu, Anda mendapatkan redaman cahaya kuadrat sebagai hasilnya (bukan linier dalam kasus sebelumnya), yang bahkan lebih baik, karena cahaya IRL telah menunjukkan memiliki kuadratik falloff.

Terima kasih semuanya atas bantuan Anda!

cubrman
sumber
13
Lapisan. Shader adalah 16bytes sejajar. Dan jika Anda melihat bagaimana kode ini diformat, Anda akan melihat bahwa itu akan dikemas menjadi dua float4. Mengapa tidak menyimpan sesuatu yang bermanfaat saat Anda mendapatkannya dari bebas dari cache?
Tordin

Jawaban:

23

Ini hanyalah semacam optimasi mengingat bahwa invSqrRadius = 1/SqrRadius, alih-alih menghitung jari-jari kuadrat terbalik untuk setiap cahaya setiap kali mereka menyimpannya, alasannya adalah bahwa pembagian biasanya merupakan operasi "lambat" setidaknya jika dibandingkan dengan perkalian.

Optimasi ini relevan terutama:

  • ketika operasi dilakukan sejumlah besar kali untuk setiap lampu, sehingga nilai caching akan membebaskan siklus CPU / GPU tambahan
  • Dan dengan asumsi waktu akses memori untuk membaca nilai sebenarnya lebih cepat daripada menghitung ulang.

Mengenai bagaimana ini digunakan, saya tidak yakin tentang implementasi spesifik mereka, tetapi mengenai 1/sqrRadius, ini hanya digunakan untuk redaman ringan, falloff dan culling. Ini juga relevan untuk pengarahan dan sorotan, satu-satunya perbedaan dalam kasus sorotan adalah bahwa Anda harus menghitung faktor sorotan setelah menerapkan pelemahan . Mengenai lampu directional seperti matahari, biasanya tidak memiliki atenuasi atau jatuh, jadi saya kira itu akan diabaikan.

[EDIT] Hanya untuk menjabarkan lebih lanjut, ini bukan data yang tidak relevan. Cahaya Irradiansi dapat dihitung menggunakan persamaan berikut:

E = Phi / 4 * pi * rSqr;

Dimana

E adalah densitas area fluks.

Phi adalah fluks cahaya.

4 * pi * rSqr adalah luas permukaan bola.

Persamaan ini menjelaskan mengapa jumlah energi yang diterima jatuh dengan jarak kuadrat.

Poin lain adalah Anda perlu menghitung jarak antara titik dan cahaya untuk menghitung kontribusi cahaya pada titik tertentu (nilai ini tidak mungkin di-cache), titik bisa masuk atau keluar rentang cahaya yang membawa kita ke titik berikutnya di mana Radius Squareberguna untuk pemusnahan.

Jika Anda ingin contoh praktis untuk menghitung falloff ringan dan pemusnahan, ini sangat berguna dalam penyaji tangguhan berbasis ubin, berikut adalah salah satu contoh .

concept3d
sumber
Kutukan, kau mengalahkanku 7 detik! ;) (dan dengan jawaban yang lebih komprehensif, juga!)
Trevor Powell
Terima kasih atas komentar terinci, terutama tautannya! Dari apa yang saya mengerti dari tautan terakhir, Battlefield 3 tidak menyimpan jari-jari tetapi jarak sebenarnya antara sumber cahaya dan penerima cahaya, bukan? Itulah nilai "d" yang mereka gunakan dalam artikel.
cubrman
@cubrman sulit berspekulasi tanpa melihat kode. Dugaan saya adalah bahwa itu adalah radius radius terbalik. Dan persamaan yang mereka gunakan mungkin sangat bervariasi dari artikel.
concept3d
Tapi katakan padaku, bagaimana Anda bisa menggunakan jari-jari cahaya terbalik terbalik dalam perhitungan pencahayaan? Setiap sumber yang saya temukan di internet memberi tahu saya bahwa saya perlu menemukan JARAK antara permukaan penerima dan sumber cahaya, bagi yang terakhir dengan jari-jari cahaya asli DAN KEMUDIAN kuadrat hasilnya. Di mana Anda pernah menggunakan radius kuadrat atau invSqrRadius? Sepertinya data yang sama sekali tidak relevan bagi saya.
cubrman
1
@cubrman memperbarui jawabannya.
concept3d
6

invSqrRadius bukan 1 - sqrRadius; ini 1 / sqrRadius.

Ini berarti bahwa Anda dapat mengalikan dengan invSqrRadius, alih-alih membaginya dengan sqrRadius (karena pembagian biasanya jauh lebih mahal daripada perkalian)

Trevor Powell
sumber
6

Jawaban lain di sini berurusan dengan jari-jari kuadrat terbalik, tapi saya akan melihat jari-jari kuadrat sebagai gantinya (yang disentuh concept3d, tapi saya percaya itu pantas didiskusikan lebih lanjut).

Apa kotak yang berguna untuk perbandingan jarak. Kita tahu bahwa menghitung jarak antara dua titik melibatkan akar kuadrat, dan akar kuadrat mahal untuk dihitung, tetapi jika semua yang ingin kita lakukan adalah membandingkan jarak (untuk menemukan mana yang kurang atau lebih besar, dan melakukan sesuatu yang menarik berdasarkan pada hasil) kita bisa membuang akar kuadrat.

Jika sqrt (x)> sqrt (y) maka itu juga halnya x> y.

Untuk cahaya, jari-jari kuadrat sama dengan jarak antara pusat cahaya dan batas maksimumnya - tentu saja kuadrat.

Untuk perhitungan pencahayaan, ini dapat digunakan untuk kasing awal. Jika jarak antara titik yang Anda pencahayaan dan pusat cahaya (kuadrat) lebih besar dari jari-jari kuadrat, titik tidak menerima cahaya dan Anda tidak perlu menjalankan sisa perhitungan Anda. Oleh karena itu ini hanya optimasi (yang cukup umum) - kita dapat menggunakan jari-jari kuadrat untuk melakukan perbandingan jarak tanpa akar kuadrat yang mahal, dan dengan biaya hanya pengurangan dan produk titik.

Aku, tentu saja, tidak tahu apakah ini adalah persis apa yang BF3 yang menggunakannya, tapi aku akan berharap bahwa aku tidak terlalu jauh dari sasaran.

Maximus Minimus
sumber
Jadi jika saya mengerti Anda dengan benar, kodenya adalah: if (dot ((lightPos - surfacePos), (lightPos - surfacePos))> lightRadiusSqr) tidak melakukan pencahayaan, bukan?
cubrman