void LightTracer::traceSample(PathSampleGenerator &sampler) { float lightPdf; const Primitive *light = chooseLightAdjoint(sampler, lightPdf); const Medium *medium = light->extMedium().get(); PositionSample point; if (!light->samplePosition(sampler, point)) return; DirectionSample direction; if (!light->sampleDirection(sampler, point, direction)) return; sampler.advancePath(); Vec3f throughput(point.weight/lightPdf); LensSample splat; if (_settings.minBounces == 0 && !light->isInfinite() && _scene->cam().sampleDirect(point.p, sampler, splat)) { Ray shadowRay(point.p, splat.d); shadowRay.setFarT(splat.dist); Vec3f transmission = generalizedShadowRay(shadowRay, medium, nullptr, 0); if (transmission != 0.0f) { Vec3f value = throughput*transmission*splat.weight *light->evalDirectionalEmission(point, DirectionSample(splat.d)); _splatBuffer->splatFiltered(splat.pixel, value); } } sampler.advancePath(); Ray ray(point.p, direction.d); throughput *= direction.weight; VolumeScatterEvent volumeEvent; SurfaceScatterEvent surfaceEvent; IntersectionTemporary data; IntersectionInfo info; Medium::MediumState state; state.reset(); Vec3f emission(0.0f); int bounce = 0; bool wasSpecular = true; bool didHit = _scene->intersect(ray, data, info); while ((didHit || medium) && bounce < _settings.maxBounces - 1) { bool hitSurface = true; if (medium) { volumeEvent = VolumeScatterEvent(&sampler, throughput, ray.pos(), ray.dir(), ray.farT()); if (!medium->sampleDistance(volumeEvent, state)) break; throughput *= volumeEvent.weight; volumeEvent.weight = Vec3f(1.0f); hitSurface = volumeEvent.t == volumeEvent.maxT; if (hitSurface && !didHit) break; } if (hitSurface) { surfaceEvent = makeLocalScatterEvent(data, info, ray, &sampler); Vec3f weight; Vec2f pixel; if (surfaceLensSample(_scene->cam(), surfaceEvent, medium, bounce + 1, ray, weight, pixel)) _splatBuffer->splatFiltered(pixel, weight*throughput); if (!handleSurface(surfaceEvent, data, info, medium, bounce, true, false, ray, throughput, emission, wasSpecular, state)) break; } else { volumeEvent.p += volumeEvent.t*volumeEvent.wi; Vec3f weight; Vec2f pixel; if (volumeLensSample(_scene->cam(), volumeEvent, medium, bounce + 1, ray, weight, pixel)) _splatBuffer->splatFiltered(pixel, weight*throughput); if (!handleVolume(volumeEvent, medium, bounce, true, false, ray, throughput, emission, wasSpecular, state)) break; } if (throughput.max() == 0.0f) break; if (std::isnan(ray.dir().sum() + ray.pos().sum())) break; if (std::isnan(throughput.sum())) break; sampler.advancePath(); bounce++; if (bounce < _settings.maxBounces) didHit = _scene->intersect(ray, data, info); } }
void PhotonTracer::tracePhoton(SurfacePhotonRange &surfaceRange, VolumePhotonRange &volumeRange, PathSampleGenerator &sampler) { float lightPdf; const Primitive *light = chooseLightAdjoint(sampler, lightPdf); PositionSample point; if (!light->samplePosition(sampler, point)) return; DirectionSample direction; if (!light->sampleDirection(sampler, point, direction)) return; sampler.advancePath(); Ray ray(point.p, direction.d); Vec3f throughput(point.weight*direction.weight/lightPdf); SurfaceScatterEvent event; IntersectionTemporary data; IntersectionInfo info; Medium::MediumState state; state.reset(); Vec3f emission(0.0f); const Medium *medium = nullptr; // TODO: Media int bounce = 0; bool wasSpecular = true; bool hitSurface = true; bool didHit = _scene->intersect(ray, data, info); while ((didHit || medium) && bounce < _settings.maxBounces - 1) { if (medium) { MediumSample mediumSample; if (!medium->sampleDistance(sampler, ray, state, mediumSample)) break; throughput *= mediumSample.weight; hitSurface = mediumSample.exited; if (!hitSurface) { if (!volumeRange.full()) { VolumePhoton &p = volumeRange.addPhoton(); p.pos = mediumSample.p; p.dir = ray.dir(); p.power = throughput; } PhaseSample phaseSample; if (!mediumSample.phase->sample(sampler, ray.dir(), phaseSample)) break; ray = ray.scatter(mediumSample.p, phaseSample.w, 0.0f); ray.setPrimaryRay(false); throughput *= phaseSample.weight; } } if (hitSurface) { if (!info.bsdf->lobes().isPureSpecular() && !surfaceRange.full()) { Photon &p = surfaceRange.addPhoton(); p.pos = info.p; p.dir = ray.dir(); p.power = throughput*std::abs(info.Ns.dot(ray.dir())/info.Ng.dot(ray.dir())); } } if (volumeRange.full() && surfaceRange.full()) break; if (hitSurface) { event = makeLocalScatterEvent(data, info, ray, &sampler); if (!handleSurface(event, data, info, medium, bounce, true, false, ray, throughput, emission, wasSpecular, state)) break; } if (throughput.max() == 0.0f) break; if (std::isnan(ray.dir().sum() + ray.pos().sum())) break; if (std::isnan(throughput.sum())) break; sampler.advancePath(); bounce++; if (bounce < _settings.maxBounces) didHit = _scene->intersect(ray, data, info); } }