Vec3f TraceBase::volumeLightSample(PathSampleGenerator &sampler, MediumSample &mediumSample, const Primitive &light, const Medium *medium, int bounce, const Ray &parentRay) { LightSample lightSample; if (!light.sampleDirect(_threadId, mediumSample.p, sampler, lightSample)) return Vec3f(0.0f); Vec3f f = mediumSample.phase->eval(parentRay.dir(), lightSample.d); if (f == 0.0f) return Vec3f(0.0f); Ray ray = parentRay.scatter(mediumSample.p, lightSample.d, 0.0f); ray.setPrimaryRay(false); IntersectionTemporary data; IntersectionInfo info; Vec3f e = attenuatedEmission(sampler, light, medium, lightSample.dist, data, info, bounce, false, ray, nullptr); if (e == 0.0f) return Vec3f(0.0f); Vec3f lightF = f*e/lightSample.pdf; if (!light.isDirac()) lightF *= SampleWarp::powerHeuristic(lightSample.pdf, mediumSample.phase->pdf(parentRay.dir(), lightSample.d)); return lightF; }
Vec3f TraceBase::attenuatedEmission(PathSampleGenerator &sampler, const Primitive &light, const Medium *medium, float expectedDist, IntersectionTemporary &data, IntersectionInfo &info, int bounce, bool startsOnSurface, Ray &ray, Vec3f *transmittance) { CONSTEXPR float fudgeFactor = 1.0f + 1e-3f; if (light.isDirac()) { ray.setFarT(expectedDist); } else { if (!light.intersect(ray, data) || ray.farT()*fudgeFactor < expectedDist) return Vec3f(0.0f); } info.p = ray.pos() + ray.dir()*ray.farT(); info.w = ray.dir(); light.intersectionInfo(data, info); Vec3f shadow = generalizedShadowRay(sampler, ray, medium, &light, startsOnSurface, true, bounce); if (transmittance) *transmittance = shadow; if (shadow == 0.0f) return Vec3f(0.0f); return shadow*light.evalDirect(data, info); }
Vec3f TraceBase::volumeSampleDirect(const Primitive &light, PathSampleGenerator &sampler, MediumSample &mediumSample, const Medium *medium, int bounce, const Ray &parentRay) { Vec3f result = volumeLightSample(sampler, mediumSample, light, medium, bounce, parentRay); if (!light.isDirac()) result += volumePhaseSample(light, sampler, mediumSample, medium, bounce, parentRay); return result; }
Vec3f TraceBase::sampleDirect(const Primitive &light, SurfaceScatterEvent &event, const Medium *medium, int bounce, const Ray &parentRay, Vec3f *transmittance) { Vec3f result(0.0f); if (event.info->bsdf->lobes().isPureSpecular() || event.info->bsdf->lobes().isForward()) return Vec3f(0.0f); result += lightSample(light, event, medium, bounce, parentRay, transmittance); if (!light.isDirac()) result += bsdfSample(light, event, medium, bounce, parentRay); return result; }
Vec3f TraceBase::lightSample(const Primitive &light, SurfaceScatterEvent &event, const Medium *medium, int bounce, const Ray &parentRay, Vec3f *transmittance) { LightSample sample; if (!light.sampleDirect(_threadId, event.info->p, *event.sampler, sample)) return Vec3f(0.0f); event.wo = event.frame.toLocal(sample.d); if (!isConsistent(event, sample.d)) return Vec3f(0.0f); bool geometricBackside = (sample.d.dot(event.info->Ng) < 0.0f); medium = event.info->primitive->selectMedium(medium, geometricBackside); event.requestedLobe = BsdfLobes::AllButSpecular; Vec3f f = event.info->bsdf->eval(event, false); if (f == 0.0f) return Vec3f(0.0f); Ray ray = parentRay.scatter(event.info->p, sample.d, event.info->epsilon); ray.setPrimaryRay(false); IntersectionTemporary data; IntersectionInfo info; Vec3f e = attenuatedEmission(*event.sampler, light, medium, sample.dist, data, info, bounce, true, ray, transmittance); if (e == 0.0f) return Vec3f(0.0f); Vec3f lightF = f*e/sample.pdf; if (!light.isDirac()) lightF *= SampleWarp::powerHeuristic(sample.pdf, event.info->bsdf->pdf(event)); return lightF; }