예제 #1
0
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;
}
예제 #2
0
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);
    }
}
예제 #3
0
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);
    }
}