void RoughCoatBsdf::substrateEvalAndPdf(const SurfaceScatterEvent &event, float eta,
        float Fi, float cosThetaTi, float &pdf, Vec3f &brdf) const
{
    const Vec3f &wi = event.wi;
    const Vec3f &wo = event.wo;

    float cosThetaTo;
    float Fo = Fresnel::dielectricReflectance(eta, wo.z(), cosThetaTo);

    if (Fi == 1.0f || Fo == 1.0f) {
        pdf = 0.0f;
        brdf = Vec3f(0.0f);
        return;
    }

    Vec3f wiSubstrate(wi.x()*eta, wi.y()*eta, std::copysign(cosThetaTi, wi.z()));
    Vec3f woSubstrate(wo.x()*eta, wo.y()*eta, std::copysign(cosThetaTo, wo.z()));

    pdf = _substrate->pdf(event.makeWarpedQuery(wiSubstrate, woSubstrate));
    pdf *= eta*eta*std::abs(wo.z()/cosThetaTo);

    float compressionProjection = eta*eta*wo.z()/cosThetaTo;

    Vec3f substrateF = _substrate->eval(event.makeWarpedQuery(wiSubstrate, woSubstrate));

    if (_scaledSigmaA.max() > 0.0f)
        substrateF *= std::exp(_scaledSigmaA*(-1.0f/cosThetaTo - 1.0f/cosThetaTi));

    brdf = compressionProjection*(1.0f - Fi)*(1.0f - Fo)*substrateF;
}
float RoughCoatBsdf::pdf(const SurfaceScatterEvent &event) const
{
    bool sampleR = event.requestedLobe.test(BsdfLobes::GlossyReflectionLobe);
    bool sampleT = event.requestedLobe.test(_substrate->lobes());

    if (!sampleT && !sampleR)
        return 0.0f;
    if (event.wi.z() <= 0.0f || event.wo.z() <= 0.0f)
        return 0.0f;

    const Vec3f &wi = event.wi;
    const Vec3f &wo = event.wo;
    float eta = 1.0f/_ior;

    float cosThetaTi, cosThetaTo;
    float Fi = Fresnel::dielectricReflectance(eta, wi.z(), cosThetaTi);
    float Fo = Fresnel::dielectricReflectance(eta, wo.z(), cosThetaTo);

    float specularProbability;
    if (sampleR && sampleT) {
        float substrateWeight = _avgTransmittance*(1.0f - Fi);
        float specularWeight = Fi;
        specularProbability = specularWeight/(specularWeight + substrateWeight);
    } else {
        specularProbability = sampleR ? 1.0f : 0.0f;
    }

    float glossyPdf = 0.0f;
    if (sampleR)
        glossyPdf = RoughDielectricBsdf::pdfBase(event, true, false, (*_roughness)[*event.info].x(), _ior, _distribution);

    float substratePdf = 0.0f;
    if (sampleT) {
        if (Fi < 1.0f && Fo < 1.0f) {
            Vec3f wiSubstrate(wi.x()*eta, wi.y()*eta, std::copysign(cosThetaTi, wi.z()));
            Vec3f woSubstrate(wo.x()*eta, wo.y()*eta, std::copysign(cosThetaTo, wo.z()));

            substratePdf = _substrate->pdf(event.makeWarpedQuery(wiSubstrate, woSubstrate));
            substratePdf *= eta*eta*std::abs(wo.z()/cosThetaTo);
        }
    }

    return glossyPdf*specularProbability + substratePdf*(1.0f - specularProbability);
}
Vec3f RoughCoatBsdf::eval(const SurfaceScatterEvent &event) const
{
    bool sampleR = event.requestedLobe.test(BsdfLobes::GlossyReflectionLobe);
    bool sampleT = event.requestedLobe.test(_substrate->lobes());

    if (!sampleT && !sampleR)
        return Vec3f(0.0f);
    if (event.wi.z() <= 0.0f || event.wo.z() <= 0.0f)
        return Vec3f(0.0f);

    Vec3f glossyR(0.0f);
    if (sampleR)
        glossyR = RoughDielectricBsdf::evalBase(event, true, false, (*_roughness)[*event.info].x(), _ior, _distribution);


    Vec3f substrateR(0.0f);
    if (sampleT) {
        const Vec3f &wi = event.wi;
        const Vec3f &wo = event.wo;
        float eta = 1.0f/_ior;

        float cosThetaTi, cosThetaTo;
        float Fi = Fresnel::dielectricReflectance(eta, wi.z(), cosThetaTi);
        float Fo = Fresnel::dielectricReflectance(eta, wo.z(), cosThetaTo);

        if (Fi == 1.0f || Fo == 1.0f)
            return glossyR;

        Vec3f wiSubstrate(wi.x()*eta, wi.y()*eta, std::copysign(cosThetaTi, wi.z()));
        Vec3f woSubstrate(wo.x()*eta, wo.y()*eta, std::copysign(cosThetaTo, wo.z()));

        float compressionProjection = eta*eta*wo.z()/cosThetaTo;

        Vec3f substrateF = _substrate->eval(event.makeWarpedQuery(wiSubstrate, woSubstrate));

        if (_scaledSigmaA.max() > 0.0f)
            substrateF *= std::exp(_scaledSigmaA*(-1.0f/cosThetaTo - 1.0f/cosThetaTi));

        substrateR = compressionProjection*(1.0f - Fi)*(1.0f - Fo)*substrateF;
    }

    return glossyR + substrateR;
}