Untuk memahami Roulette Rusia, mari kita lihat pelacak jalur mundur yang sangat mendasar:
void RenderPixel(uint x, uint y, UniformSampler *sampler) {
Ray ray = m_scene->Camera.CalculateRayFromPixel(x, y, sampler);
float3 color(0.0f);
float3 throughput(1.0f);
// Bounce the ray around the scene
for (uint bounces = 0; bounces < 10; ++bounces) {
m_scene->Intersect(ray);
// The ray missed. Return the background color
if (ray.geomID == RTC_INVALID_GEOMETRY_ID) {
color += throughput * float3(0.846f, 0.933f, 0.949f);
break;
}
// We hit an object
// Fetch the material
Material *material = m_scene->GetMaterial(ray.geomID);
// The object might be emissive. If so, it will have a corresponding light
// Otherwise, GetLight will return nullptr
Light *light = m_scene->GetLight(ray.geomID);
// If we hit a light, add the emmisive light
if (light != nullptr) {
color += throughput * light->Le();
}
float3 normal = normalize(ray.Ng);
float3 wo = normalize(-ray.dir);
float3 surfacePos = ray.org + ray.dir * ray.tfar;
// Get the new ray direction
// Choose the direction based on the material
float3 wi = material->Sample(wo, normal, sampler);
float pdf = material->Pdf(wi, normal);
// Accumulate the brdf attenuation
throughput = throughput * material->Eval(wi, wo, normal) / pdf;
// Shoot a new ray
// Set the origin at the intersection point
ray.org = surfacePos;
// Reset the other ray properties
ray.dir = wi;
ray.tnear = 0.001f;
ray.tfar = embree::inf;
ray.geomID = RTC_INVALID_GEOMETRY_ID;
ray.primID = RTC_INVALID_GEOMETRY_ID;
ray.instID = RTC_INVALID_GEOMETRY_ID;
ray.mask = 0xFFFFFFFF;
ray.time = 0.0f;
}
m_scene->Camera.FrameBuffer.SplatPixel(x, y, color);
}
YAITU. kami melompat-lompat di sekitar tempat kejadian, mengumpulkan warna dan redaman cahaya saat kami pergi. Agar benar-benar tidak bias secara matematis, pantulan harus menuju tak terhingga. Tapi ini tidak realistis, dan seperti yang Anda catat, tidak perlu secara visual; untuk sebagian besar adegan, setelah sejumlah pantulan, katakanlah 10, jumlah kontribusi terhadap warna akhir sangat sangat minim.
Jadi untuk menghemat sumber daya komputasi, banyak pelacak jalur memiliki batasan keras untuk jumlah bouncing. Ini menambah bias.
Yang mengatakan, sulit untuk memilih apa batas yang seharusnya. Beberapa adegan tampak hebat setelah 2 memantul; yang lain (katakanlah dengan transmisi atau SSS) dapat memakan waktu hingga 10 atau 20.
Jika kita memilih terlalu rendah, gambar akan terlihat bias. Tetapi jika kita memilih terlalu tinggi, kita membuang-buang energi dan waktu perhitungan.
Salah satu cara untuk memecahkan ini, seperti yang Anda catat, adalah mengakhiri jalur setelah kami mencapai ambang pelemahan. Ini juga menambah bias.
Menjepit setelah ambang batas, akan berhasil , tetapi sekali lagi, bagaimana kita memilih ambang batas? Jika kita memilih terlalu besar, gambar akan terlihat bias, terlalu kecil, dan kita membuang-buang sumber daya.
Roulette Rusia berupaya menyelesaikan masalah ini dengan cara yang tidak bias. Pertama, ini kodenya:
void RenderPixel(uint x, uint y, UniformSampler *sampler) {
Ray ray = m_scene->Camera.CalculateRayFromPixel(x, y, sampler);
float3 color(0.0f);
float3 throughput(1.0f);
// Bounce the ray around the scene
for (uint bounces = 0; bounces < 10; ++bounces) {
m_scene->Intersect(ray);
// The ray missed. Return the background color
if (ray.geomID == RTC_INVALID_GEOMETRY_ID) {
color += throughput * float3(0.846f, 0.933f, 0.949f);
break;
}
// We hit an object
// Fetch the material
Material *material = m_scene->GetMaterial(ray.geomID);
// The object might be emissive. If so, it will have a corresponding light
// Otherwise, GetLight will return nullptr
Light *light = m_scene->GetLight(ray.geomID);
// If we hit a light, add the emmisive light
if (light != nullptr) {
color += throughput * light->Le();
}
float3 normal = normalize(ray.Ng);
float3 wo = normalize(-ray.dir);
float3 surfacePos = ray.org + ray.dir * ray.tfar;
// Get the new ray direction
// Choose the direction based on the material
float3 wi = material->Sample(wo, normal, sampler);
float pdf = material->Pdf(wi, normal);
// Accumulate the brdf attenuation
throughput = throughput * material->Eval(wi, wo, normal) / pdf;
// Russian Roulette
// Randomly terminate a path with a probability inversely equal to the throughput
float p = std::max(throughput.x, std::max(throughput.y, throughput.z));
if (sampler->NextFloat() > p) {
break;
}
// Add the energy we 'lose' by randomly terminating paths
throughput *= 1 / p;
// Shoot a new ray
// Set the origin at the intersection point
ray.org = surfacePos;
// Reset the other ray properties
ray.dir = wi;
ray.tnear = 0.001f;
ray.tfar = embree::inf;
ray.geomID = RTC_INVALID_GEOMETRY_ID;
ray.primID = RTC_INVALID_GEOMETRY_ID;
ray.instID = RTC_INVALID_GEOMETRY_ID;
ray.mask = 0xFFFFFFFF;
ray.time = 0.0f;
}
m_scene->Camera.FrameBuffer.SplatPixel(x, y, color);
}
Roulette Rusia mengakhiri jalur secara acak dengan probabilitas berbanding terbalik dengan throughput. Jadi jalur dengan throughput rendah yang tidak akan berkontribusi banyak ke tempat kejadian lebih mungkin untuk diakhiri.
Jika kita berhenti di situ, kita masih bias. Kita 'kehilangan' energi dari jalan yang kita hentikan secara acak. Untuk membuatnya tidak bias, kami meningkatkan energi jalur non-terminasi dengan probabilitas mereka untuk dihentikan. Ini, bersama dengan menjadi acak, membuat Roulette Rusia tidak bias.
Untuk menjawab pertanyaan terakhir Anda:
- Apakah Russian Roulette memberikan hasil yang tidak bias?
- Apakah Roulette Rusia diperlukan untuk hasil yang tidak bias?
- Tergantung pada apa yang Anda maksud dengan tidak bias. Jika Anda maksud secara matematis, maka ya. Namun, jika maksud Anda secara visual, maka tidak. Anda hanya harus memilih Anda kedalaman jalur maks dan ambang batas cutoff dengan sangat hati-hati. Ini bisa sangat membosankan karena bisa berubah dari satu adegan ke adegan lainnya.
- Bisakah Anda menggunakan probabilitas tetap (cut-off), dan kemudian mendistribusikan kembali energi 'hilang'. Apakah ini tidak bias?
- Jika Anda menggunakan probabilitas tetap, Anda menambahkan bias. Dengan mendistribusikan kembali energi 'hilang', Anda mengurangi bias, tetapi masih bias secara matematis. Agar sama sekali tidak bias, itu harus acak.
- Jika energi yang akan hilang dengan menghentikan sinar tanpa mendistribusikan energi, akhirnya akan hilang pula (karena sinar yang didistribusikan juga akhirnya diakhiri), bagaimana cara ini memperbaiki situasi?
- Roulette Rusia hanya menghentikan pantulannya. Itu tidak menghapus sampel sepenuhnya. Juga, energi 'hilang' diperhitungkan dalam bouncing hingga penghentian. Jadi satu-satunya cara agar energi 'akhirnya hilang' adalah memiliki ruang yang sepenuhnya hitam.
Pada akhirnya, Russian Roulette adalah algoritma yang sangat sederhana yang menggunakan sejumlah kecil sumber daya komputasi ekstra. Sebagai gantinya, ini dapat menghemat sejumlah besar sumber daya komputasi. Karena itu, saya tidak dapat benar-benar melihat alasan untuk tidak menggunakannya.
to be completely unbiased it must be random
. Saya pikir Anda masih bisa mendapatkan hasil matematika-ok dengan menggunakan sampel fraksional weigthing, daripada lulus biner / menjatuhkan bahwa roulette Rusia memaksakan, hanya saja roulette akan konvergen lebih cepat karena mengoperasikan sampel kepentingan yang sangat penting.Teknik roulette Rusia itu sendiri adalah cara mengakhiri jalur tanpa memperkenalkan bias sistemik. Prinsipnya cukup mudah: jika pada titik tertentu Anda memiliki peluang 10% untuk secara sewenang-wenang mengganti energi dengan 0, dan jika Anda melakukannya berkali-kali, Anda akan melihat energi 10% lebih sedikit. Peningkatan energi hanya mengimbangi itu. Jika Anda tidak mengkompensasi energi yang hilang karena pemutusan jalur, maka roulette Rusia akan menjadi bias, tetapi seluruh teknik adalah metode yang berguna untuk menghindari bias.
Jika saya seorang musuh yang ingin membuktikan bahwa teknik "terminasi jalur yang kontribusinya kurang dari nilai tetap kecil" bias, saya akan membuat adegan dengan cahaya yang sangat redup sehingga jalur yang berkontribusi selalu lebih kecil dari nilai itu. Mungkin saya mensimulasikan kamera rendah cahaya.
Tapi tentu saja Anda selalu dapat mengekspos nilai tetap sebagai parameter yang dapat diubah-ubah kepada pengguna, sehingga mereka dapat menjatuhkannya lebih jauh jika adegan mereka kurang cahaya. Jadi mari kita abaikan contoh itu sebentar.
Apa yang terjadi jika saya menganggap objek yang diterangi oleh banyak jalur berenergi sangat rendah yang dikumpulkan oleh a reflektor parabola ? Jalur energi rendah tidak harus terpental secara membabi buta dengan cara yang bisa Anda abaikan sepenuhnya. Alasan yang sama berlaku untuk, misalnya, memotong jalur setelah sejumlah terpental: Anda dapat membuat adegan dengan jalur yang memantulkan serangkaian 20 cermin sebelum mengenai suatu objek.
Cara lain untuk melihatnya: jika Anda menetapkan kontribusi jalur ke 0 setelah jatuh di bawah beberapa epsilon tetap, bagaimana Anda memperbaiki kehilangan energi itu? Anda tidak hanya mengurangi energi total dengan sebagian kecil. Anda tidak tahu apa-apa tentang berapa banyak energi yang Anda abaikan, karena Anda memotong pada ambang batas kontribusi sebelum Anda tahu faktor lain: energi kejadian.
sumber
Hanya untuk memperluas pada beberapa jawaban lain, bukti bahwa Roulette Rusia tidak memberikan hasil yang bias sangat sederhana.
Ganti setiap istilah dengan:
Kemudian:
sumber