void PathCPURenderThread::DirectLightSampling( const float u0, const float u1, const float u2, const float u3, const float u4, const Spectrum &pathThrouput, const BSDF &bsdf, const int depth, Spectrum *radiance) { PathCPURenderEngine *engine = (PathCPURenderEngine *)renderEngine; Scene *scene = engine->renderConfig->scene; if (!bsdf.IsDelta()) { // Pick a light source to sample float lightPickPdf; const LightSource *light = scene->SampleAllLights(u0, &lightPickPdf); Vector lightRayDir; float distance, directPdfW; Spectrum lightRadiance = light->Illuminate(scene, bsdf.hitPoint, u1, u2, u3, &lightRayDir, &distance, &directPdfW); if (!lightRadiance.Black()) { BSDFEvent event; float bsdfPdfW; Spectrum bsdfEval = bsdf.Evaluate(lightRayDir, &event, &bsdfPdfW); if (!bsdfEval.Black()) { const float epsilon = Max(MachineEpsilon::E(bsdf.hitPoint), MachineEpsilon::E(distance)); Ray shadowRay(bsdf.hitPoint, lightRayDir, epsilon, distance - epsilon); RayHit shadowRayHit; BSDF shadowBsdf; Spectrum connectionThroughput; // Check if the light source is visible if (!scene->Intersect(device, false, u4, &shadowRay, &shadowRayHit, &shadowBsdf, &connectionThroughput)) { const float cosThetaToLight = AbsDot(lightRayDir, bsdf.shadeN); const float directLightSamplingPdfW = directPdfW * lightPickPdf; const float factor = cosThetaToLight / directLightSamplingPdfW; if (depth >= engine->rrDepth) { // Russian Roulette bsdfPdfW *= Max(bsdfEval.Filter(), engine->rrImportanceCap); } // MIS between direct light sampling and BSDF sampling const float weight = PowerHeuristic(directLightSamplingPdfW, bsdfPdfW); *radiance += (weight * factor) * pathThrouput * connectionThroughput * lightRadiance * bsdfEval; } } } } }
void PathHybridState::DirectLightSampling(const PathHybridRenderThread *renderThread, const float u0, const float u1, const float u2, const float u3, const BSDF &bsdf) { if (!bsdf.IsDelta()) { PathHybridRenderEngine *renderEngine = (PathHybridRenderEngine *)renderThread->renderEngine; Scene *scene = renderEngine->renderConfig->scene; // Pick a light source to sample float lightPickPdf; const LightSource *light = scene->SampleAllLights(u0, &lightPickPdf); Vector lightRayDir; float distance, directPdfW; Spectrum lightRadiance = light->Illuminate(*scene, bsdf.hitPoint.p, u1, u2, u3, &lightRayDir, &distance, &directPdfW); if (!lightRadiance.Black()) { BSDFEvent event; float bsdfPdfW; Spectrum bsdfEval = bsdf.Evaluate(lightRayDir, &event, &bsdfPdfW); if (!bsdfEval.Black()) { const float epsilon = Max(MachineEpsilon::E(bsdf.hitPoint.p), MachineEpsilon::E(distance)); directLightRay = Ray(bsdf.hitPoint.p, lightRayDir, epsilon, distance - epsilon); const float cosThetaToLight = AbsDot(lightRayDir, bsdf.hitPoint.shadeN); const float directLightSamplingPdfW = directPdfW * lightPickPdf; const float factor = cosThetaToLight / directLightSamplingPdfW; if (depth >= renderEngine->rrDepth) { // Russian Roulette bsdfPdfW *= RenderEngine::RussianRouletteProb(bsdfEval, renderEngine->rrImportanceCap); } // MIS between direct light sampling and BSDF sampling const float weight = PowerHeuristic(directLightSamplingPdfW, bsdfPdfW); directLightRadiance = (weight * factor) * throuput * lightRadiance * bsdfEval; } else directLightRadiance = Spectrum(); } else directLightRadiance = Spectrum(); } else directLightRadiance = Spectrum(); }
void LightCPURenderThread::ConnectToEye(const float u0, const BSDF &bsdf, const Point &lensPoint, const Spectrum &flux, vector<SampleResult> &sampleResults) { LightCPURenderEngine *engine = (LightCPURenderEngine *)renderEngine; Scene *scene = engine->renderConfig->scene; Vector eyeDir(bsdf.hitPoint - lensPoint); const float eyeDistance = eyeDir.Length(); eyeDir /= eyeDistance; BSDFEvent event; Spectrum bsdfEval = bsdf.Evaluate(-eyeDir, &event); if (!bsdfEval.Black()) { const float epsilon = Max(MachineEpsilon::E(lensPoint), MachineEpsilon::E(eyeDistance)); Ray eyeRay(lensPoint, eyeDir, epsilon, eyeDistance - epsilon); float scrX, scrY; if (scene->camera->GetSamplePosition(lensPoint, eyeDir, eyeDistance, &scrX, &scrY)) { RayHit eyeRayHit; BSDF bsdfConn; Spectrum connectionThroughput; if (!scene->Intersect(device, true, u0, &eyeRay, &eyeRayHit, &bsdfConn, &connectionThroughput)) { // Nothing was hit, the light path vertex is visible const float cosToCamera = Dot(bsdf.shadeN, -eyeDir); const float cosAtCamera = Dot(scene->camera->GetDir(), eyeDir); const float cameraPdfW = 1.f / (cosAtCamera * cosAtCamera * cosAtCamera * scene->camera->GetPixelArea()); const float cameraPdfA = PdfWtoA(cameraPdfW, eyeDistance, cosToCamera); const float fluxToRadianceFactor = cameraPdfA; const Spectrum radiance = connectionThroughput * flux * fluxToRadianceFactor * bsdfEval; AddSampleResult(sampleResults, PER_SCREEN_NORMALIZED, scrX, scrY, radiance, 1.f); } } } }