Пример #1
0
bool ThinSheetBsdf::sample(SurfaceScatterEvent &event) const
{
    if (!event.requestedLobe.test(BsdfLobes::SpecularReflectionLobe))
        return false;

    event.wo = Vec3f(-event.wi.x(), -event.wi.y(), event.wi.z());
    event.pdf = 1.0f;
    event.sampledLobe = BsdfLobes::SpecularReflectionLobe;

    if (_sigmaA == 0.0f && !_enableInterference) {
        // Fast path / early out
        event.weight = Vec3f(1.0f);
        return true;
    }

    float thickness = (*_thickness)[*event.info].x();

    float cosThetaT;
    if (_enableInterference) {
        event.weight = Fresnel::thinFilmReflectanceInterference(1.0f/_ior,
                std::abs(event.wi.z()), thickness*500.0f, cosThetaT);
    } else {
        event.weight = Vec3f(Fresnel::thinFilmReflectance(1.0f/_ior,
                std::abs(event.wi.z()), cosThetaT));
    }

    Vec3f transmittance = 1.0f - event.weight;
    if (_sigmaA != 0.0f && cosThetaT > 0.0f)
        transmittance *= std::exp(-_sigmaA*(thickness*2.0f/cosThetaT));

    event.weight /= 1.0f - transmittance.avg();

    return true;
}
Пример #2
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;
}
Пример #3
0
float ExponentialMedium::pdf(PathSampleGenerator &/*sampler*/, const Ray &ray, bool onSurface) const
{
    if (_absorptionOnly) {
        return 1.0f;
    } else {
        float  x = _falloffScale*(ray.pos() - _unitPoint).dot(_unitFalloffDirection);
        float dx = _falloffScale*ray.dir().dot(_unitFalloffDirection);

        Vec3f transmittance = std::exp(-_sigmaT*densityIntegral(x, dx, ray.farT()));
        if (onSurface) {
            return transmittance.avg();
        } else {
            return (density(x, dx, ray.farT())*_sigmaT*transmittance).avg();
        }
    }
}
Пример #4
0
Vec3f HomogeneousMedium::transmittanceAndPdfs(PathSampleGenerator &/*sampler*/, const Ray &ray, bool startOnSurface,
        bool endOnSurface, float &pdfForward, float &pdfBackward) const
{
    if (ray.farT() == Ray::infinity()) {
        pdfForward = pdfBackward = 0.0f;
        return Vec3f(0.0f);
    } else if (_absorptionOnly) {
        pdfForward = pdfBackward = 1.0f;
        return std::exp(-_sigmaT*ray.farT());
    } else {
        Vec3f weight = std::exp(-_sigmaT*ray.farT());
        pdfForward  =   endOnSurface ? weight.avg() : (_sigmaT*weight).avg();
        pdfBackward = startOnSurface ? weight.avg() : (_sigmaT*weight).avg();
        return weight;
    }
}
Пример #5
0
float AtmosphericMedium::pdf(PathSampleGenerator &/*sampler*/, const Ray &ray, bool onSurface) const
{
    if (_absorptionOnly) {
        return 1.0f;
    } else {
        Vec3f p = (ray.pos() - _center);
        float t0 = p.dot(ray.dir());
        float t1 = ray.farT() + t0;
        float  h = (p - t0*ray.dir()).length();

        Vec3f transmittance = std::exp(-_sigmaT*densityIntegral(h, t0, t1));
        if (onSurface) {
            return transmittance.avg();
        } else {
            return (density(h, t0)*_sigmaT*transmittance).avg();
        }
    }
}
Пример #6
0
Vec3f AtmosphericMedium::transmittanceAndPdfs(PathSampleGenerator &/*sampler*/, const Ray &ray, bool startOnSurface,
        bool endOnSurface, float &pdfForward, float &pdfBackward) const
{
    Vec3f p = (ray.pos() - _center);
    float t0 = p.dot(ray.dir());
    float t1 = ray.farT() + t0;
    float  h = (p - t0*ray.dir()).length();

    Vec3f transmittance = std::exp(-_sigmaT*densityIntegral(h, t0, t1));

    if (_absorptionOnly) {
        pdfForward = pdfBackward = 1.0f;
    } else {
        pdfForward  =   endOnSurface ? transmittance.avg() : (density(h, t1)*_sigmaT*transmittance).avg();
        pdfBackward = startOnSurface ? transmittance.avg() : (density(h, t0)*_sigmaT*transmittance).avg();
    }

    return transmittance;
}
Пример #7
0
Vec3f ExponentialMedium::transmittanceAndPdfs(PathSampleGenerator &/*sampler*/, const Ray &ray, bool startOnSurface,
        bool endOnSurface, float &pdfForward, float &pdfBackward) const
{
    float  x = _falloffScale*(ray.pos() - _unitPoint).dot(_unitFalloffDirection);
    float dx = _falloffScale*ray.dir().dot(_unitFalloffDirection);

    if (ray.farT() == Ray::infinity() && dx <= 0.0f) {
        pdfForward = pdfBackward = 0.0f;
        return Vec3f(0.0f);
    }

    Vec3f transmittance = std::exp(-_sigmaT*densityIntegral(x, dx, ray.farT()));

    if (_absorptionOnly) {
        pdfForward = pdfBackward = 1.0f;
    } else {
        pdfForward  =   endOnSurface ? transmittance.avg() : (density(x, dx, ray.farT())*_sigmaT*transmittance).avg();
        pdfBackward = startOnSurface ? transmittance.avg() : (density(x, dx,       0.0f)*_sigmaT*transmittance).avg();
    }

    return transmittance;
}
Пример #8
0
Vec3f PhotonTracer::traceSample(Vec2u pixel, const KdTree<Photon> &surfaceTree,
        const KdTree<VolumePhoton> *mediumTree, PathSampleGenerator &sampler,
        float gatherRadius)
{
    PositionSample point;
    if (!_scene->cam().samplePosition(sampler, point))
        return Vec3f(0.0f);
    DirectionSample direction;
    if (!_scene->cam().sampleDirection(sampler, point, pixel, direction))
        return Vec3f(0.0f);
    sampler.advancePath();

    Vec3f throughput = point.weight*direction.weight;
    Ray ray(point.p, direction.d);
    ray.setPrimaryRay(true);

    IntersectionTemporary data;
    IntersectionInfo info;
    const Medium *medium = _scene->cam().medium().get();

    Vec3f result(0.0f);
    int bounce = 0;
    bool didHit = _scene->intersect(ray, data, info);
    while ((medium || didHit) && bounce < _settings.maxBounces - 1) {
        if (medium) {
            if (mediumTree) {
                Vec3f beamEstimate(0.0f);
                mediumTree->beamQuery(ray.pos(), ray.dir(), ray.farT(), [&](const VolumePhoton &p, float t, float distSq) {
                    Ray mediumQuery(ray);
                    mediumQuery.setFarT(t);
                    beamEstimate += (3.0f*INV_PI*sqr(1.0f - distSq/p.radiusSq))/p.radiusSq
                            *medium->phaseFunction(p.pos)->eval(ray.dir(), -p.dir)
                            *medium->transmittance(mediumQuery)*p.power;
                });
                result += throughput*beamEstimate;
            }
            throughput *= medium->transmittance(ray);
        }
        if (!didHit)
            break;

        const Bsdf &bsdf = *info.bsdf;

        SurfaceScatterEvent event = makeLocalScatterEvent(data, info, ray, &sampler);

        Vec3f transparency = bsdf.eval(event.makeForwardEvent(), false);
        float transparencyScalar = transparency.avg();

        Vec3f wo;
        if (sampler.nextBoolean(DiscreteTransparencySample, transparencyScalar)) {
            wo = ray.dir();
            throughput *= transparency/transparencyScalar;
        } else {
            event.requestedLobe = BsdfLobes::SpecularLobe;
            if (!bsdf.sample(event, false))
                break;

            wo = event.frame.toGlobal(event.wo);

            throughput *= event.weight;
        }

        bool geometricBackside = (wo.dot(info.Ng) < 0.0f);
        medium = info.primitive->selectMedium(medium, geometricBackside);

        ray = ray.scatter(ray.hitpoint(), wo, info.epsilon);

        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);
    }

    if (!didHit) {
        if (!medium && _scene->intersectInfinites(ray, data, info))
            result += throughput*info.primitive->evalDirect(data, info);
        return result;
    }
    if (info.primitive->isEmissive())
        result += throughput*info.primitive->evalDirect(data, info);

    int count = surfaceTree.nearestNeighbours(ray.hitpoint(), _photonQuery.get(), _distanceQuery.get(),
            _settings.gatherCount, gatherRadius);
    if (count == 0)
        return result;

    const Bsdf &bsdf = *info.bsdf;
    SurfaceScatterEvent event = makeLocalScatterEvent(data, info, ray, &sampler);

    Vec3f surfaceEstimate(0.0f);
    for (int i = 0; i < count; ++i) {
        event.wo = event.frame.toLocal(-_photonQuery[i]->dir);
        // Asymmetry due to shading normals already compensated for when storing the photon,
        // so we don't use the adjoint BSDF here
        surfaceEstimate += _photonQuery[i]->power*bsdf.eval(event, false)/std::abs(event.wo.z());
    }
    float radiusSq = count == int(_settings.gatherCount) ? _distanceQuery[0] : gatherRadius*gatherRadius;
    result += throughput*surfaceEstimate*(INV_PI/radiusSq);

    return result;
}
Пример #9
0
inline Vec3f TraceBase::generalizedShadowRayImpl(PathSampleGenerator &sampler,
                           Ray &ray,
                           const Medium *medium,
                           const Primitive *endCap,
                           int bounce,
                           bool startsOnSurface,
                           bool endsOnSurface,
                           float &pdfForward,
                           float &pdfBackward) const
{
    IntersectionTemporary data;
    IntersectionInfo info;

    float initialFarT = ray.farT();
    Vec3f throughput(1.0f);
    do {
        bool didHit = _scene->intersect(ray, data, info) && info.primitive != endCap;
        if (didHit) {
            if (!info.bsdf->lobes().hasForward())
                return Vec3f(0.0f);

            SurfaceScatterEvent event = makeLocalScatterEvent(data, info, ray, nullptr);

            // For forward events, the transport direction does not matter (since wi = -wo)
            Vec3f transparency = info.bsdf->eval(event.makeForwardEvent(), false);
            if (transparency == 0.0f)
                return Vec3f(0.0f);

            if (ComputePdfs) {
                float transparencyScalar = transparency.avg();
                pdfForward  *= transparencyScalar;
                pdfBackward *= transparencyScalar;
            }

            throughput *= transparency;
            bounce++;

            if (bounce >= _settings.maxBounces)
                return Vec3f(0.0f);
        }

        if (medium) {
            if (ComputePdfs) {
                float forward, backward;
                throughput *= medium->transmittanceAndPdfs(sampler, ray, startsOnSurface, didHit || endsOnSurface, forward, backward);
                pdfForward *= forward;
                pdfBackward *= backward;
            } else {
                throughput *= medium->transmittance(sampler, ray, startsOnSurface, endsOnSurface);
            }
        }
        if (info.primitive == nullptr || info.primitive == endCap)
            return bounce >= _settings.minBounces ? throughput : Vec3f(0.0f);
        medium = info.primitive->selectMedium(medium, !info.primitive->hitBackside(data));
        startsOnSurface = true;

        ray.setPos(ray.hitpoint());
        initialFarT -= ray.farT();
        ray.setNearT(info.epsilon);
        ray.setFarT(initialFarT);
    } while(true);
    return Vec3f(0.0f);
}