void PathCPURenderThread::DirectHitFiniteLight( const bool lastSpecular, const Spectrum &pathThrouput, const float distance, const BSDF &bsdf, const float lastPdfW, Spectrum *radiance) { PathCPURenderEngine *engine = (PathCPURenderEngine *)renderEngine; Scene *scene = engine->renderConfig->scene; float directPdfA; const Spectrum emittedRadiance = bsdf.GetEmittedRadiance(scene, &directPdfA); if (!emittedRadiance.Black()) { float weight; if (!lastSpecular) { const float lightPickProb = scene->PickLightPdf(); const float directPdfW = PdfAtoW(directPdfA, distance, AbsDot(bsdf.fixedDir, bsdf.shadeN)); // MIS between BSDF sampling and direct light sampling weight = PowerHeuristic(lastPdfW, directPdfW * lightPickProb); } else weight = 1.f; *radiance += pathThrouput * weight * emittedRadiance; } }
void PathHybridState::DirectHitFiniteLight(const Scene *scene, const float distance, const BSDF &bsdf) { float directPdfA; const Spectrum emittedRadiance = bsdf.GetEmittedRadiance(&directPdfA); if (!emittedRadiance.Black()) { float weight; if (!lastSpecular) { const float lightPickProb = scene->PickLightPdf(); const float directPdfW = PdfAtoW(directPdfA, distance, AbsDot(bsdf.hitPoint.fixedDir, bsdf.hitPoint.shadeN)); // MIS between BSDF sampling and direct light sampling weight = PowerHeuristic(lastPdfW, directPdfW * lightPickProb); } else weight = 1.f; sampleResults[0].radiance += throuput * weight * emittedRadiance; } }
void LightCPURenderThread::TraceEyePath(Sampler *sampler, vector<SampleResult> *sampleResults) { LightCPURenderEngine *engine = (LightCPURenderEngine *)renderEngine; Scene *scene = engine->renderConfig->scene; PerspectiveCamera *camera = scene->camera; Film *film = threadFilm; const u_int filmWidth = film->GetWidth(); const u_int filmHeight = film->GetHeight(); // Sample offsets const u_int sampleBootSize = 11; const u_int sampleEyeStepSize = 3; Ray eyeRay; const float screenX = min(sampler->GetSample(0) * filmWidth, (float)(filmWidth - 1)); const float screenY = min(sampler->GetSample(1) * filmHeight, (float)(filmHeight - 1)); camera->GenerateRay(screenX, screenY, &eyeRay, sampler->GetSample(9), sampler->GetSample(10)); Spectrum radiance, eyePathThroughput(1.f, 1.f, 1.f); int depth = 1; while (depth <= engine->maxPathDepth) { const u_int sampleOffset = sampleBootSize + (depth - 1) * sampleEyeStepSize; RayHit eyeRayHit; BSDF bsdf; Spectrum connectionThroughput; const bool somethingWasHit = scene->Intersect(device, false, sampler->GetSample(sampleOffset), &eyeRay, &eyeRayHit, &bsdf, &connectionThroughput); if (!somethingWasHit) { // Nothing was hit, check infinite lights (including sun) const Spectrum throughput = eyePathThroughput * connectionThroughput; if (scene->envLight) radiance += throughput * scene->envLight->GetRadiance(scene, -eyeRay.d); if (scene->sunLight) radiance += throughput * scene->sunLight->GetRadiance(scene, -eyeRay.d); break; } else { // Something was hit, check if it is a light source if (bsdf.IsLightSource()) radiance = eyePathThroughput * connectionThroughput * bsdf.GetEmittedRadiance(scene); else { // Check if it is a specular bounce float bsdfPdf; Vector sampledDir; BSDFEvent event; float cosSampleDir; const Spectrum bsdfSample = bsdf.Sample(&sampledDir, sampler->GetSample(sampleOffset + 1), sampler->GetSample(sampleOffset + 2), &bsdfPdf, &cosSampleDir, &event); if (bsdfSample.Black() || ((depth == 1) && !(event & SPECULAR))) break; // If depth = 1 and it is a specular bounce, I continue to trace the // eye path looking for a light source eyePathThroughput *= connectionThroughput * bsdfSample * (cosSampleDir / bsdfPdf); assert (!eyePathThroughput.IsNaN() && !eyePathThroughput.IsInf()); eyeRay = Ray(bsdf.hitPoint, sampledDir); } ++depth; } } // Add a sample even if it is black in order to avoid aliasing problems // between sampled pixel and not sampled one (in PER_PIXEL_NORMALIZED buffer) AddSampleResult(*sampleResults, PER_PIXEL_NORMALIZED, screenX, screenY, radiance, (depth == 1) ? 1.f : 0.f); }