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.