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