パストレーシング / Path Tracing

パストレーシング / 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/

Twitter: @Shocker_0x15

367b44575446a2eccc58feea183c1475?s=128

shocker_0x15

August 29, 2015
Tweet

Transcript

  1. 2.

    ϨϯμϦϯάํఔࣜ 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
  2. 5.

    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 )
  3. 9.

    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; } γϟυ΢ϨΠΛඈ͹ͯ͠ःณΛνΣοΫ ःณ͕ແ͚Ε͹د༩Λ஝ੵ
  4. 10.
  5. 11.

    // 光源上の点を明示的にサンプルして現在の点と接続 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߲ͭͱڑ཭ͷೋ৐ ͔֬ʹͦΕͬΆ͍߲͕ͩ ϨϯμϦϯάํఔࣜʹͦΜͳ߲͚͋ͬͨͬʁʁ
  6. 12.

    ແ͍ DPT߲ͻͱͭͩ͠ڑ཭ೋ৐΋ແ͍ Lo (x, o ) = Le (x, o

    ) + S2 Li (x, i )fs (x, i, o ) |n · i | d i
  7. 14.

    ֬཰ʹ୯Ґ͸ແ͍͕֬཰ີ౓ 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]
  8. 15.

    Ґஔʹؔ͢ΔαϯϓϦϯάͰ͸ ѻ͏ϨϯμϦϯάํఔ͕ࣜएׯมΘΔ Lo (x x ) = Le (x x

    ) + M Li (x x)fs (x x x )G(x x )dA x x x x ੵ෼߲͸γʔϯதͷ෺ମද໘ɹ্ͷੵ෼ͱͯ͠มܗ͞ΕΔ M زԿ߲ɹ͸ੵ෼ͷม਺ม׵ͷ݁Ռ ϠίϏΞϯ  G
  9. 22.

    ޫݯ໘ͷαϯϓϦϯά #4%'ͷαϯϓϦϯά n  VEACH, E. 1997. Robust Monte Carlo methods

    for light transport simulation. PhD thesis, Stanford, CA, USA.
  10. 23.

    ଟॏॏ఺తαϯϓϦϯά 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 ) ϛοΫεʂ
  11. 24.

    .*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ͷ୯ҐΛ߹ΘͤΔඞཁ͕͋Δ)
  12. 25.

    όϥϯεώϡʔϦεςΟοΫɿཁ͢Δʹ BSDF ʮύε͖࣋ͬͯͨΑʯ ʮਪఆ݁Ռʹࣗ৴ͷ΄Ͳ͸ʯ BSDF ʮʯ ʮMJHIU͕Ծʹ͜ͷύεͭͬͨ͘ͳΒࣗ৴͸ʯ lightʮʯ ʮ͡Ό͋#4%'͕͖࣋ͬͯͨύεͷॏΈ͸ ɹ

      ͬͯ͜ͱͰʯ lightʮύε͖࣋ͬͯͨΑʯ ʮਪఆ݁Ռʹࣗ৴ͷ΄Ͳ͸ʯ lightʮʯ ʮ#4%'͕Ծʹ͜ͷύεͭͬͨ͘ͳΒࣗ৴͸ʯ BSDF ʮʯ ʮ͡Ό͋MJHIU͕͖࣋ͬͯͨύεͷॏΈ͸ ɹ   ͬͯ͜ͱͰʯ
  13. 26.
  14. 27.

    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΢ΣΠτ
  15. 28.

    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΢ΣΠτ
  16. 30.

    ബϨϯζϞσϧΛ༻͍ͨ%P'දݱ ཧ࿦ɾखॱͷৄࡉ͸8&#ϖʔδࢀর ୺తʹड़΂Δͱʜ xp x0 x1 x1 x0 xp x1

    γʔϯதͷҐஔ ηϯαʔ໘ ෺໘ Ϩϯζ্ͷ఺ɹΛαϯϓϧɺ ϐΫηϧதͷҐஔɹʹରԠ͢Δ෺໘্ͷ఺ɹʹ޲͔ͬͯϨΠτϨʔε ϨϯζҐஔͷαϯϓϧΛߦ͍ͬͯΔͷͰ1%'ɹɹɹͰد༩ΛׂΔ pA (x0 )