$30 off During Our Annual Pro Sale. View Details »

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

https://twitter.com/Shocker_0x15

shocker_0x15

August 29, 2015
Tweet

More Decks by shocker_0x15

Other Decks in Technology

Transcript

  1. ύετϨʔγϯά
    ౉෦৺
    !4IPDLFS@Y
    ϨΠτϨ߹॓
    https://sites.google.com/site/raytracingcamp3/
    PATH TRACING

    View Slide

  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

    View Slide

  3. ೖࣹํ޲Λ֬཰తʹαϯϓϧɺޫݯʹ౰ͨΕ͹د༩Λܭࢉ
    ࢹ఺͔Βޫ༌ૹܦ࿏ΛτϨʔε

    View Slide

  4. ೖࣹํ޲ͷαϯϓϦϯά
    %JGGVTF#4%' (MPTTZ#4%' 4QFDVMBS#4%'
    Ͳͷํ޲΋ࣅͨΑ͏ͳ஋ ڸ໘൓ࣹํ޲ͷ
    पғʹେ͖ͳ஋
    ڸ໘൓ࣹํ޲Ҏ֎ͷ
    ஋͸θϩ
    গͳ͘ͱ΋#4%'͕େ͖ͳ஋Λ࣋ͭํ޲Λ
    ଟ͘αϯϓϧ͢Δͷ͕๬·͍͠à#4%'ͷॏ఺తαϯϓϦϯά

    View Slide

  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
    )

    View Slide

  6. ೖࣹํ޲Λ֬཰తʹαϯϓϧɺޫݯʹ౰ͨΕ͹د༩͕ͱΕΔ
    ࢹ఺͔Βޫ༌ૹܦ࿏ΛτϨʔε
    ͳ͔ͳ͔౰ͨΒͳ͍ʂ(ಛʹޫݯ͕খ͍͞ͱ͖)

    View Slide

  7. NEXT EVENT ESTIMATION

    View Slide

  8. NEXT EVENT ESTIMATION
    ޫݯ্ͷ఺Λ໌ࣔతʹαϯϓϧɺࢹઢܦ࿏ͱ઀ଓ͢Δ

    View Slide

  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;

    }

    γϟυ΢ϨΠΛඈ͹ͯ͠ःณΛνΣοΫ
    ःณ͕ແ͚Ε͹د༩Λ஝ੵ

    View Slide

  10. ʁʁʁ

    View Slide

  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߲ͭͱڑ཭ͷೋ৐
    ͔֬ʹͦΕͬΆ͍߲͕ͩ
    ϨϯμϦϯάํఔࣜʹͦΜͳ߲͚͋ͬͨͬʁʁ

    View Slide

  12. ແ͍
    DPT߲ͻͱͭͩ͠ڑ཭ೋ৐΋ແ͍
    Lo
    (x, o
    ) = Le
    (x, o
    ) +
    S2
    Li
    (x, i
    )fs
    (x, i, o
    ) |n · i
    | d i

    View Slide

  13. ୯Ґͷ࿩

    View Slide

  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]

    View Slide

  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

    View Slide

  16. #4%'ͷαϯϓϦϯά /FYU&WFOU&TUJNBUJPO
    ͨͩ͠/FYU&WFOU&TUJNBUJPO͕ٯޮՌʹͳΔ͜ͱ΋

    View Slide

  17. MULTIPLE IMPORTANCE SAMPLING
    ଟॏॏ఺తαϯϓϦϯά

    View Slide

  18. Light
    ޫ୔BSDF
    #4%'ͷد༩ʹԊͬͨॏ఺తαϯϓϦϯά
    #4%'د༩ʹԊͬͯೖࣹํ޲αϯϓϧɿߴ͍֬཰Ͱߴ͍د༩
    à௿͍෼ࢄ ޫݯ͕ྑ͍৔ॴʹ͋Ε͹

    C =
    1
    N
    N
    i=1
    f(¯
    xi
    )
    pBSDF

    xi
    )

    View Slide

  19. Light
    ֦ࢄBSDF
    #4%'ͷد༩ʹԊͬͨॏ఺తαϯϓϦϯά
    #4%'د༩ʹԊͬͯೖࣹํ޲αϯϓϧɿ௿͍֬཰Ͱߴ͍د༩
    àߴ͍෼ࢄ ͨ·ʹ͔͠౰ͨΒͳ͍ͨΊ

    C =
    1
    N
    N
    i=1
    f(¯
    xi
    )
    pBSDF

    xi
    )

    View Slide

  20. Light
    ֦ࢄBSDF
    ޫݯ্ͷҐஔͷॏ఺తαϯϓϦϯά
    ޫݯ্ͷҐஔΛαϯϓϧͯ͠઀ଓɿߴ͍֬཰Ͱߴ͍د༩
    à௿͍෼ࢄ #4%'ͷ஋͕ൺֱతҰ༷Ͱ͋Ε͹

    C =
    1
    N
    N
    i=1
    f(¯
    xi
    )
    plight

    xi
    )

    View Slide

  21. Light
    ޫ୔BSDF
    ޫݯ্ͷҐஔͷॏ఺తαϯϓϦϯά
    ޫݯ্ͷҐஔΛαϯϓϧͯ͠઀ଓɿ௿͍֬཰Ͱߴ͍د༩
    àߴ͍෼ࢄ #4%'ͷ஋͕ඇҰ༷ͳͨΊ

    C =
    1
    N
    N
    i=1
    f(¯
    xi
    )
    plight

    xi
    )

    View Slide

  22. ޫݯ໘ͷαϯϓϦϯά
    #4%'ͷαϯϓϦϯά
    n  VEACH, E. 1997. Robust Monte Carlo methods for light transport simulation. PhD thesis, Stanford, CA, USA.

    View Slide

  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
    )
    ϛοΫεʂ

    View Slide

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

    View Slide

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

    View Slide

  26. .*4ʹΑΔ΢ΣΠτ഑෼
    .VMUJQMF*NQPSUBODF4BNQMJOH
    n  VEACH, E. 1997. Robust Monte Carlo methods for light transport simulation. PhD thesis, Stanford, CA, USA.

    View Slide

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

    View Slide

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

    View Slide

  29. DEPTH OF FIELD
    ඃࣸքਂ౓

    View Slide

  30. ബϨϯζϞσϧΛ༻͍ͨ%P'දݱ
    ཧ࿦ɾखॱͷৄࡉ͸8ϖʔδࢀর
    ୺తʹड़΂Δͱʜ
    xp
    x0
    x1
    x1
    x0
    xp x1
    γʔϯதͷҐஔ
    ηϯαʔ໘
    ෺໘
    Ϩϯζ্ͷ఺ɹΛαϯϓϧɺ
    ϐΫηϧதͷҐஔɹʹରԠ͢Δ෺໘্ͷ఺ɹʹ޲͔ͬͯϨΠτϨʔε
    ϨϯζҐஔͷαϯϓϧΛߦ͍ͬͯΔͷͰ1%'ɹɹɹͰد༩ΛׂΔ
    pA
    (x0
    )

    View Slide

  31. ࣮૷͢Δͱʜ
    ϐϯϗʔϧ ബϨϯζϞσϧʹΑΔ%P'

    View Slide

  32. ͪΌΜͱϘέͯΔΈ͍͚ͨͩͲ
    ϐϯϗʔϧͱ໌Δ͞ҧ͏͠ɺ
    Ϩϯζͷେ͖͞ʹΑͬͯ໌Δ͞มΘΔʜ
    ݱ࣮ͷΧϝϥͱҰॹ
    Ϩϯζ͕େ͖͚Ε͹औΓೖΕΔޫͷྔ͕૿͑ͯ໌Δ͘ͳΔ
    àը૾ͷ໌Δ͞ΛҰఆʹอ͍ͪͨͷͳΒ
    ηϯαʔͷײ౓Λมߋ͢Δඞཁ͕͋Δ

    View Slide

  33. ηϯαʔͷײ౓Λద੾ʹઃఆ͢Δͱʜ
    ϐϯϗʔϧ ബϨϯζϞσϧʹΑΔ%P'

    View Slide

  34. ͪΐͬͱ଴ͯ

    View Slide

  35. ϐϯϗʔϧΧϝϥ͸ബϨϯζϞσϧͰ
    Ϩϯζ͕ۃݶʹখ͍͞৔߹ͱଊ͑Δ͜ͱ͕Ͱ͖Δ
    à1%'ͷ஋͕ແݶͱͳΔͷͰɺ1%'ͰׂΔͱ݁Ռ͸θϩ
    Ϩϯζ͕େ͖͍ఔը૾͕໌Δ͍ͷ͸౰ͨΓલ
    ͡Ό͋ϐϯϗʔϧΧϝϥͷը૾͸ਅͬ҉ͳͷͰ͸ʜʁ
    ͋Δҙຯਖ਼ղ
    ॳาతͳύετϨ౳ͷ࣮૷Ͱ͸
    ͦ΋ͦ΋Ϩϯζ໘ͷ1%'ͰׂͬͨΓ͍ͯ͠ͳ͍
    à1%'ΛΩϟϯηϧ͢Δ͚ͩͷ
    ແݶͷηϯαʔײ౓͕͋Δͷͱ౳͍͠

    View Slide

  36. ͓͠·͍
    *#-ͱ͔৭ʑ࿩͔͚ͨͬͨ͠Ͳ
    ͦͷ͏ͪ8ϖʔδʹॻ͖·͢
    IUUQTSBZTQBDFYZ[$(

    View Slide