bool TraceBase::handleSurface(SurfaceScatterEvent &event, IntersectionTemporary &data, IntersectionInfo &info, const Medium *&medium, int bounce, bool adjoint, bool enableLightSampling, Ray &ray, Vec3f &throughput, Vec3f &emission, bool &wasSpecular, Medium::MediumState &state, Vec3f *transmittance) { const Bsdf &bsdf = *info.bsdf; // For forward events, the transport direction does not matter (since wi = -wo) Vec3f transparency = bsdf.eval(event.makeForwardEvent(), false); float transparencyScalar = transparency.avg(); Vec3f wo; if (event.sampler->nextBoolean(transparencyScalar) ){ wo = ray.dir(); event.pdf = transparencyScalar; event.weight = transparency/transparencyScalar; event.sampledLobe = BsdfLobes::ForwardLobe; throughput *= event.weight; } else { if (!adjoint) { if (enableLightSampling && bounce < _settings.maxBounces - 1) emission += estimateDirect(event, medium, bounce + 1, ray, transmittance)*throughput; if (info.primitive->isEmissive() && bounce >= _settings.minBounces) { if (!enableLightSampling || wasSpecular || !info.primitive->isSamplable()) emission += info.primitive->evalDirect(data, info)*throughput; } } event.requestedLobe = BsdfLobes::AllLobes; if (!bsdf.sample(event, adjoint)) return false; wo = event.frame.toGlobal(event.wo); if (!isConsistent(event, wo)) return false; throughput *= event.weight; wasSpecular = event.sampledLobe.hasSpecular(); if (!wasSpecular) ray.setPrimaryRay(false); } bool geometricBackside = (wo.dot(info.Ng) < 0.0f); medium = info.primitive->selectMedium(medium, geometricBackside); state.reset(); ray = ray.scatter(ray.hitpoint(), wo, info.epsilon); return true; }
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); } }