void Light::SHProject(const PbrtPoint &p, float pEpsilon, int lmax, const Scene *scene, bool computeLightVisibility, float time, RNG &rng, Spectrum *coeffs) const { for (int i = 0; i < SHTerms(lmax); ++i) coeffs[i] = 0.f; uint32_t ns = RoundUpPow2(nSamples); uint32_t scramble1D = rng.RandomUInt(); uint32_t scramble2D[2] = { rng.RandomUInt(), rng.RandomUInt() }; float *Ylm = ALLOCA(float, SHTerms(lmax)); for (uint32_t i = 0; i < ns; ++i) { // Compute incident radiance sample from _light_, update SH _coeffs_ float u[2], pdf; Sample02(i, scramble2D, u); LightSample lightSample(u[0], u[1], VanDerCorput(i, scramble1D)); Vector wi; VisibilityTester vis; Spectrum Li = Sample_L(p, pEpsilon, lightSample, time, &wi, &pdf, &vis); if (!Li.IsBlack() && pdf > 0.f && (!computeLightVisibility || vis.Unoccluded(scene))) { // Add light sample contribution to MC estimate of SH coefficients SHEvaluate(wi, lmax, Ylm); for (int j = 0; j < SHTerms(lmax); ++j) coeffs[j] += Li * Ylm[j] / (pdf * ns); } } }
Spectrum InfiniteAreaLightIS::Sample_L(const Point &p, Vector *wi, VisibilityTester *visibility) const { float pdf; Spectrum L = Sample_L(p, RandomFloat(), RandomFloat(), wi, &pdf, visibility); if (pdf == 0.) return Spectrum(0.); return L / pdf; }
Spectrum DistantLight::Sample_L(const Point &p, float u1, float u2, Vector *wi, float *pdf, VisibilityTester *visibility) const { *pdf = 1.f; return Sample_L(p, wi, visibility); }
bool Shade(Path* path, Geometry *geometry, BVHAccel *bvh, const RayHit& rayHit) { uint tracedShadowRayCount; if (rayHit.index == 0xffffffffu) { return false; } // Something was hit unsigned int currentTriangleIndex = rayHit.index; RGB triInterpCol = geometry->triangles[currentTriangleIndex].InterpolateColor( geometry->vertColors, rayHit.b1, rayHit.b2); Normal shadeN = geometry->triangles[currentTriangleIndex].InterpolateNormal( geometry->vertNormals, rayHit.b1, rayHit.b2); // Calculate next step path->depth++; // Check if I have to stop if (path->depth >= MAX_PATH_DEPTH) { // Too depth, terminate the path return false; } else if (path->depth > 2) { // Russian Rulette, maximize cos const float p = min(1.f, triInterpCol.filter() * AbsDot(shadeN, path->pathRay.d)); if (p > getFloatRNG(&path->seed)) path->throughput /= p; else { // Terminate the path return false; } } //-------------------------------------------------------------------------- // Build the shadow ray //-------------------------------------------------------------------------- // Check if it is a light source float RdotShadeN = Dot(path->pathRay.d, shadeN); if (geometry->IsLight(currentTriangleIndex)) { // Check if we are on the right side of the light source if ((path->depth == 1) && (RdotShadeN < 0.f)) path->radiance += triInterpCol * path->throughput; // Terminate the path return false; } if (RdotShadeN > 0.f) { // Flip shade normal shadeN = -shadeN; } else RdotShadeN = -RdotShadeN; path->throughput *= RdotShadeN * triInterpCol; // Trace shadow rays const Point hitPoint = path->pathRay(rayHit.t); tracedShadowRayCount = 0; const float lightStrategyPdf = static_cast<float> (SHADOWRAY) / static_cast<float> (geometry->nLights); float lightPdf[SHADOWRAY]; RGB lightColor[SHADOWRAY]; Ray shadowRay[SHADOWRAY]; for (unsigned int i = 0; i < SHADOWRAY; ++i) { // Select the light to sample const unsigned int currentLightIndex = geometry->SampleLights(getFloatRNG(&path->seed)); // const TriangleLight &light = scene->lights[currentLightIndex]; // Select a point on the surface lightColor[tracedShadowRayCount] = Sample_L(currentLightIndex, geometry, hitPoint, shadeN, getFloatRNG(&path->seed), getFloatRNG(&path->seed), &lightPdf[tracedShadowRayCount], &shadowRay[tracedShadowRayCount]); // Scale light pdf for ONE_UNIFORM strategy lightPdf[tracedShadowRayCount] *= lightStrategyPdf; // Using 0.1 instead of 0.0 to cut down fireflies if (lightPdf[tracedShadowRayCount] > 0.1f) tracedShadowRayCount++; } RayHit* rh = new RayHit[tracedShadowRayCount]; for (unsigned int i = 0; i < tracedShadowRayCount; ++i) Intersect(shadowRay[i], rh[i], bvh->bvhTree, geometry->triangles, geometry->vertices); if ((tracedShadowRayCount > 0)) { for (unsigned int i = 0; i < tracedShadowRayCount; ++i) { const RayHit *shadowRayHit = &rh[i]; if (shadowRayHit->index == 0xffffffffu) { // Nothing was hit, light is visible path->radiance += path->throughput * lightColor[i] / lightPdf[i]; } } } //-------------------------------------------------------------------------- // Build the next vertex path ray //-------------------------------------------------------------------------- // Calculate exit direction float r1 = 2.f * M_PI * getFloatRNG(&path->seed); float r2 = getFloatRNG(&path->seed); float r2s = sqrt(r2); const Vector w(shadeN); Vector u; if (fabsf(shadeN.x) > .1f) { const Vector a(0.f, 1.f, 0.f); u = Cross(a, w); } else { const Vector a(1.f, 0.f, 0.f); u = Cross(a, w); } u = Normalize(u); Vector v = Cross(w, u); Vector newDir = u * (cosf(r1) * r2s) + v * (sinf(r1) * r2s) + w * sqrtf(1.f - r2); newDir = Normalize(newDir); path->pathRay.o = hitPoint; path->pathRay.d = newDir; return true; }