Share
Embed
パストレーシング / Path Tracing
レイトレ合宿3!!!のセミナーで使用した資料です。
スライドの趣旨:パストレーシングの基礎概念からおさらいしてNext Event EstimationとMultiple Importance Samplingまで。
主な対象者:モンテカルロ積分の基礎を理解しており、簡単なパストレーシングなどの実装経験がある方。
2017/12/8: パストレーシングの理論と実装について記事を書いています。
https://rayspace.xyz/CG/contents/path_tracing/
https://rayspace.xyz/CG/contents/path_tracing_implementation/
https://twitter.com/Shocker_0x15
shocker_0x15
August 29, 2015
Transcript
36 slides
-
ϨϯμϦϯάํఔࣜ Lo (x, o ) = Le (x, o )
+ S2 Li (x, i )fs (x, i, o ) |n · i | d i ϞϯςΧϧϩ .$ ੵ Lo (x, o ) = Le (x, o ) + Li (x, i )fs (x, i, o ) |n · i | p ( i ) ϥϯμϜʹαϯϓϧ͞Εͨೖࣹํ i p ( i ) ɹΛαϯϓϧ͢Δ֬ີ 1%' i -
ೖࣹํͷαϯϓϦϯά %JGGVTF#4%' (MPTTZ#4%' 4QFDVMBS#4%' ͲͷํࣅͨΑ͏ͳ ڸ໘ࣹํͷ पғʹେ͖ͳ ڸ໘ࣹํҎ֎ͷ θϩ গͳ͘ͱ#4%'͕େ͖ͳΛ࣋ͭํΛ
ଟ͘αϯϓϧ͢Δͷ͕·͍͠à#4%'ͷॏతαϯϓϦϯά -
for (int j = 0; j < ImageHeight; ++j) {
for (int i = 0; i < ImageWidth; ++i) { px = i + rnd01(); py = j + rnd01(); ray, We, dirPDF = sampleCameraRay(px, py); alpha *= We / dirPDF; // シーンと交叉判定 hit, surfPt = intersect(ray); if (!hit) break; while (true) { ... ray = Ray(surfPt.p, dir); // シーンと交叉判定 hit, surfPt = intersect(ray); if (!hit) break; // Russian Roulette if (rnd01() >= ProbRR) break; alpha /= ProbRR; } } } // 光源にヒットした場合、寄与を蓄積 if (surfPt.isEmitting()) contribution += alpha * surfPt.Le(-ray.dir); // BSDFの重点的サンプリング fs, dir, dirPDF = surfPt.BSDF.sample(rnd01(), rnd01()); alpha *= fs * absDot(surfPt.n, dir) / dirPDF; ϨϯμϦϯάํఔࣜ ͷ.$ੵ ͦͷ·· Li (x, i )fs (x, i, o ) |n · i | p ( i ) -
for (int j = 0; j < ImageHeight; ++j) {
for (int i = 0; i < ImageWidth; ++i) { px = i + rnd01(); py = j + rnd01(); ray, We, dirPDF = sampleCameraRay(px, py); alpha *= We / dirPDF; // シーンと交叉判定 hit, surfPt = intersect(ray); if (!hit) break; if (surfPt.isEmitting()) contribution += alpha * surfPt.Le(-ray.dir); while (true) { ... // BSDFの重点的サンプリング fs, dir, dirPDF = surfPt.BSDF.sample(rnd01(), rnd01()); alpha *= fs * absDot(surfPt.n, dir) / dirPDF; ray = Ray(surfPt.p, dir); // シーンと交叉判定 hit, surfPt = intersect(ray); if (!hit) break; // Russian Roulette if (rnd01() >= ProbRR) break; alpha /= ProbRR; } } } // 光源上の点を明示的にサンプルして現在の点と接続 lightSurfPt, areaPDF = sampleLightPoint(rnd01(), rnd01()); if (unoccluded(surfPt, lightSurfPt)) { shadowDir = normalize(lightSurfPt.p – surfPt.p); fs = surfPt.BSDF.eval(shadowDir, -ray.dir); G = absDot(surfPt.n, shadowDir) * absDot(lightSurfPt.n, shadowDir) / sqDistance(surfPt.p, lightSurfPt.p); contribution += alpha * fs * lightSurfPt.Le(-shadowDir) * G / areaPDF; } γϟυϨΠΛඈͯ͠ःณΛνΣοΫ ःณ͕ແ͚Εد༩Λੵ -
// 光源上の点を明示的にサンプルして現在の点と接続 lightSurfPt, areaPDF = sampleLightPoint(rnd01(), rnd01()); if (unoccluded(surfPt, lightSurfPt))
{ shadowDir = normalize(lightSurfPt.p – surfPt.p); fs = surfPt.BSDF.eval(shadowDir, -ray.dir); G = absDot(surfPt.n, shadowDir) * absDot(lightSurfPt.n, shadowDir) / sqDistance(surfPt.p, lightSurfPt.p); contribution += alpha * fs * lightSurfPt.Le(-shadowDir) * G / areaPDF; } ͜ΕԿʁ DPT߲ͭͱڑͷೋ ͔֬ʹͦΕͬΆ͍߲͕ͩ ϨϯμϦϯάํఔࣜʹͦΜͳ߲͚͋ͬͨͬʁʁ -
ແ͍ DPT߲ͻͱͭͩ͠ڑೋແ͍ Lo (x, o ) = Le (x, o
) + S2 Li (x, i )fs (x, i, o ) |n · i | d i -
֬ʹ୯Ґແ͍͕֬ີ 1%' ʹ୯Ґ͕͋Δ Lo (x, o ) = Le (x,
o ) + Li (x, i )fs (x, i, o ) |n · i | p ( i ) #4%'ͷαϯϓϦϯάͰೖࣹํΛαϯϓϦϯά ํ ཱମ֯ ʹؔ͢Δ1%' [sr 1] /FYU&WFOU&TUJNBUJPOͰޫݯ্ͷҐஔΛαϯϓϦϯά ମද໘্ͷҐஔ ໘ੵ ʹؔ͢Δ1%' [m 2] -
Ґஔʹؔ͢ΔαϯϓϦϯάͰ ѻ͏ϨϯμϦϯάํఔ͕ࣜएׯมΘΔ Lo (x x ) = Le (x x
) + M Li (x x)fs (x x x )G(x x )dA x x x x ੵ߲γʔϯதͷମද໘ɹ্ͷੵͱͯ͠มܗ͞ΕΔ M زԿ߲ɹੵͷมมͷ݁Ռ ϠίϏΞϯ G -
Light ޫBSDF #4%'ͷد༩ʹԊͬͨॏతαϯϓϦϯά #4%'د༩ʹԊͬͯೖࣹํαϯϓϧɿߴ͍֬Ͱߴ͍د༩ à͍ࢄ ޫݯ͕ྑ͍ॴʹ͋Ε C = 1
N N i=1 f(¯ xi ) pBSDF (¯ xi ) -
Light ֦ࢄBSDF #4%'ͷد༩ʹԊͬͨॏతαϯϓϦϯά #4%'د༩ʹԊͬͯೖࣹํαϯϓϧɿ͍֬Ͱߴ͍د༩ àߴ͍ࢄ ͨ·ʹ͔ͨ͠Βͳ͍ͨΊ C = 1
N N i=1 f(¯ xi ) pBSDF (¯ xi ) -
Light ֦ࢄBSDF ޫݯ্ͷҐஔͷॏతαϯϓϦϯά ޫݯ্ͷҐஔΛαϯϓϧͯ͠ଓɿߴ͍֬Ͱߴ͍د༩ à͍ࢄ #4%'ͷ͕ൺֱతҰ༷Ͱ͋Ε C = 1
N N i=1 f(¯ xi ) plight (¯ xi ) -
Light ޫBSDF ޫݯ্ͷҐஔͷॏతαϯϓϦϯά ޫݯ্ͷҐஔΛαϯϓϧͯ͠ଓɿ͍֬Ͱߴ͍د༩ àߴ͍ࢄ #4%'ͷ͕ඇҰ༷ͳͨΊ C = 1
N N i=1 f(¯ xi ) plight (¯ xi ) -
ޫݯ໘ͷαϯϓϦϯά #4%'ͷαϯϓϦϯά n VEACH, E. 1997. Robust Monte Carlo methods
for light transport simulation. PhD thesis, Stanford, CA, USA. -
ଟॏॏతαϯϓϦϯά C = 1 N N i=1 f(¯ xlight,i )
plight (¯ xlight,i ) C = 1 N N i=1 f(¯ xBSDF,i ) pBSDF (¯ xBSDF,i ) C = 1 N N i=1 wBSDF (¯ xBSDF,i ) f(¯ xBSDF,i ) pBSDF (¯ xBSDF,i ) + wlight (¯ xlight,i ) f(¯ xlight,i ) plight (¯ xlight,i ) ϛοΫεʂ -
.*4ΣΠτ Ұྫ: όϥϯεώϡʔϦεςΟοΫ (ΣΠτ = ͦΕͧΕͷPDFͷॏΈ͖ฏۉ) C = 1 N
N i=1 wBSDF (¯ xBSDF,i ) f(¯ xBSDF,i ) pBSDF (¯ xBSDF,i ) + wlight (¯ xlight,i ) f(¯ xlight,i ) plight (¯ xlight,i ) wBSDF (¯ x) = pBSDF (¯ x) pBSDF (¯ x) + plight (¯ x) wlight (¯ x) = plight (¯ x) pBSDF (¯ x) + plight (¯ x) (࣮ࡍʹPDFͷ୯ҐΛ߹ΘͤΔඞཁ͕͋Δ) -
όϥϯεώϡʔϦεςΟοΫɿཁ͢Δʹ BSDF ʮύε͖࣋ͬͯͨΑʯ ʮਪఆ݁Ռʹࣗ৴ͷ΄Ͳʯ BSDF ʮʯ ʮMJHIU͕Ծʹ͜ͷύεͭͬͨ͘ͳΒࣗ৴ʯ lightʮʯ ʮ͡Ό͋#4%'͕͖࣋ͬͯͨύεͷॏΈ ɹ
ͬͯ͜ͱͰʯ lightʮύε͖࣋ͬͯͨΑʯ ʮਪఆ݁Ռʹࣗ৴ͷ΄Ͳʯ lightʮʯ ʮ#4%'͕Ծʹ͜ͷύεͭͬͨ͘ͳΒࣗ৴ʯ BSDF ʮʯ ʮ͡Ό͋MJHIU͕͖࣋ͬͯͨύεͷॏΈ ɹ ͬͯ͜ͱͰʯ -
.*4ʹΑΔΣΠτ .VMUJQMF*NQPSUBODF4BNQMJOH n VEACH, E. 1997. Robust Monte Carlo methods
for light transport simulation. PhD thesis, Stanford, CA, USA. -
for (int j = 0; j < ImageHeight; ++j) {
for (int i = 0; i < ImageWidth; ++i) { px = i + rnd01(), py = j + rnd01(); ray, We, dirPDF = sampleCameraRay(px, py); alpha *= We / dirPDF; hit, surfPt = intersect(ray); if (!hit) continue; if (surfPt.isEmitting()) contribution += alpha * surfPt.Le(-ray.dir); while (true) { ... // BSDFの重点的サンプリング fs, dir, dirPDF = surfPt.BSDF.sample(rnd01(), rnd01()); alpha *= fs * absDot(surfPt.n, dir) / dirPDF; ray = Ray(surfPt.p, dir); hit, surfPt = intersect(ray); if (!hit) break; ... // Russian Roulette if (rnd01() >= ProbRR) break; alpha /= ProbRR; } } } // 光源上の点を明示的にサンプリングして現在の点と接続 lightSurfPt, lightPDF = sampleLightPoint(rnd01(), rnd01()); if (unoccluded(surfPt, lightSurfPt)) { shadowDir = normalize(lightSurfPt.p – surfPt.p); cosShd = absDot(surfPt.n, shadowDir); cosLight = absDot(lightSurfPt.n, shadowDir); dist2 = sqDistance(surfPt.p, lightSurfPt.p); fs = surfPt.BSDF.eval(shadowDir, -ray.dir); G = cosShd * cosLight / dist2; // 単位をlightPDF[m^-2]に合わせる。 bsdfPDF = surfPt.BSDF.evalDirectionalPDF(shadowDir, -ray.dir) * cosLight / dist2; MISWeight = lightPDF / (bsdfPDF + lightPDF); contribution += alpha * MISWeight * fs * lightSurfPt.Le(-shadowDir) * G / lightPDF; } /FYU&WFOU&TUJNBUJPO .*4ΣΠτ -
for (int j = 0; j < ImageHeight; ++j) {
for (int i = 0; i < ImageWidth; ++i) { px = i + rnd01(), py = j + rnd01(); ray, We, dirPDF = sampleCameraRay(px, py); alpha *= We / dirPDF; hit, surfPt = intersect(ray); if (!hit) continue; if (surfPt.isEmitting()) contribution += alpha * surfPt.Le(-ray.dir); while (true) { ... // BSDFの重点的サンプリング fs, dir, dirPDF = surfPt.BSDF.sample(rnd01(), rnd01()); alpha *= fs * absDot(surfPt.n, dir) / dirPDF; ray = Ray(surfPt.p, dir); hit, surfPt = intersect(ray); if (!hit) break; ... // Russian Roulette if (rnd01() >= ProbRR) break; alpha /= ProbRR; } } } // 光源にヒットした場合、寄与を蓄積 if (surfPt.isEmitting()) { cosLight = absDot(ray.dir, surfPt.n); dist2 = sqDistance(ray.org, surfPt.p); bsdfPDF = dirPDF; // 単位をbsdfPDF[sr^-1]に合わせる。 lightPDF = surfPt.evalAreaPDF() * dist2 / cosLight; MISWeight = bsdfPDF / (bsdfPDF + lightPDF); contribution += alpha * MISWeight * surfPt.Le(-ray.dir); } #4%'4BNQMJOH .*4ΣΠτ -
ബϨϯζϞσϧΛ༻͍ͨ%P'දݱ ཧɾखॱͷৄࡉ8&#ϖʔδࢀর తʹड़Δͱʜ xp x0 x1 x1 x0 xp x1
γʔϯதͷҐஔ ηϯαʔ໘ ໘ Ϩϯζ্ͷɹΛαϯϓϧɺ ϐΫηϧதͷҐஔɹʹରԠ͢Δ໘্ͷɹʹ͔ͬͯϨΠτϨʔε ϨϯζҐஔͷαϯϓϧΛߦ͍ͬͯΔͷͰ1%'ɹɹɹͰد༩ΛׂΔ pA (x0 )