bool RoughPlasticBsdf::sample(SurfaceScatterEvent &event) const { if (event.wi.z() <= 0.0f) return false; bool sampleR = event.requestedLobe.test(BsdfLobes::GlossyReflectionLobe); bool sampleT = event.requestedLobe.test(BsdfLobes::DiffuseReflectionLobe); if (!sampleR && !sampleT) return false; const Vec3f &wi = event.wi; float eta = 1.0f/_ior; float Fi = Fresnel::dielectricReflectance(eta, wi.z()); float substrateWeight = _substrateWeight*_avgTransmittance*(1.0f - Fi); float specularWeight = Fi; float specularProbability = specularWeight/(specularWeight + substrateWeight); if (sampleR && (event.sampler->nextBoolean(specularProbability) || !sampleT)) { float roughness = (*_roughness)[*event.info].x(); if (!RoughDielectricBsdf::sampleBase(event, true, false, roughness, _ior, _distribution)) return false; if (sampleT) { Vec3f diffuseAlbedo = albedo(event.info); float Fo = Fresnel::dielectricReflectance(eta, event.wo.z()); Vec3f brdfSubstrate = ((1.0f - Fi)*(1.0f - Fo)*eta*eta)*(diffuseAlbedo/(1.0f - diffuseAlbedo*_diffuseFresnel))*INV_PI*event.wo.z(); Vec3f brdfSpecular = event.weight*event.pdf; float pdfSubstrate = SampleWarp::cosineHemispherePdf(event.wo)*(1.0f - specularProbability); float pdfSpecular = event.pdf*specularProbability; event.weight = (brdfSpecular + brdfSubstrate)/(pdfSpecular + pdfSubstrate); event.pdf = pdfSpecular + pdfSubstrate; } return true; } else { Vec3f wo(SampleWarp::cosineHemisphere(event.sampler->next2D())); float Fo = Fresnel::dielectricReflectance(eta, wo.z()); Vec3f diffuseAlbedo = albedo(event.info); event.wo = wo; event.weight = ((1.0f - Fi)*(1.0f - Fo)*eta*eta)*(diffuseAlbedo/(1.0f - diffuseAlbedo*_diffuseFresnel)); if (_scaledSigmaA.max() > 0.0f) event.weight *= std::exp(_scaledSigmaA*(-1.0f/event.wo.z() - 1.0f/event.wi.z())); event.pdf = SampleWarp::cosineHemispherePdf(event.wo); if (sampleR) { Vec3f brdfSubstrate = event.weight*event.pdf; float pdfSubstrate = event.pdf*(1.0f - specularProbability); Vec3f brdfSpecular = RoughDielectricBsdf::evalBase(event, true, false, (*_roughness)[*event.info].x(), _ior, _distribution); float pdfSpecular = RoughDielectricBsdf::pdfBase(event, true, false, (*_roughness)[*event.info].x(), _ior, _distribution); pdfSpecular *= specularProbability; event.weight = (brdfSpecular + brdfSubstrate)/(pdfSpecular + pdfSubstrate); event.pdf = pdfSpecular + pdfSubstrate; } event.sampledLobe = BsdfLobes::DiffuseReflectionLobe; } return true; }
Vec3f RoughPlasticBsdf::eval(const SurfaceScatterEvent &event) const { bool sampleR = event.requestedLobe.test(BsdfLobes::GlossyReflectionLobe); bool sampleT = event.requestedLobe.test(BsdfLobes::DiffuseReflectionLobe); if (!sampleR && !sampleT) 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 diffuseR(0.0f); if (sampleT) { float eta = 1.0f/_ior; float Fi = Fresnel::dielectricReflectance(eta, event.wi.z()); float Fo = Fresnel::dielectricReflectance(eta, event.wo.z()); Vec3f diffuseAlbedo = albedo(event.info); diffuseR = ((1.0f - Fi)*(1.0f - Fo)*eta*eta*event.wo.z()*INV_PI)*(diffuseAlbedo/(1.0f - diffuseAlbedo*_diffuseFresnel)); if (_scaledSigmaA.max() > 0.0f) diffuseR *= std::exp(_scaledSigmaA*(-1.0f/event.wo.z() - 1.0f/event.wi.z())); } return glossyR + diffuseR; }
bool MixedBsdf::sample(SurfaceScatterEvent &event) const { float ratio; if (!adjustedRatio(event.requestedLobe, event.info, ratio)) return false; if (event.sampler->nextBoolean(ratio)) { if (!_bsdf0->sample(event)) return false; float pdf0 = event.pdf*ratio; float pdf1 = _bsdf1->pdf(event)*(1.0f - ratio); Vec3f f = event.weight*event.pdf*ratio + _bsdf1->eval(event)*(1.0f - ratio); event.pdf = pdf0 + pdf1; event.weight = f/event.pdf; } else { if (!_bsdf1->sample(event)) return false; float pdf0 = _bsdf0->pdf(event)*ratio; float pdf1 = event.pdf*(1.0f - ratio); Vec3f f = _bsdf0->eval(event)*ratio + event.weight*event.pdf*(1.0f - ratio); event.pdf = pdf0 + pdf1; event.weight = f/event.pdf; } event.weight *= albedo(event.info); return true; }
Vec3f PlasticBsdf::eval(const SurfaceScatterEvent &event) const { if (event.wi.z() <= 0.0f || event.wo.z() <= 0.0f) return Vec3f(0.0f); bool evalR = event.requestedLobe.test(BsdfLobes::SpecularReflectionLobe); bool evalT = event.requestedLobe.test(BsdfLobes::DiffuseReflectionLobe); float eta = 1.0f/_ior; float Fi = Fresnel::dielectricReflectance(eta, event.wi.z()); float Fo = Fresnel::dielectricReflectance(eta, event.wo.z()); if (evalR && checkReflectionConstraint(event.wi, event.wo)) { return Vec3f(Fi); } else if (evalT) { Vec3f diffuseAlbedo = albedo(event.info); Vec3f brdf = ((1.0f - Fi)*(1.0f - Fo)*eta*eta*event.wo.z()*INV_PI)* (diffuseAlbedo/(1.0f - diffuseAlbedo*_diffuseFresnel)); if (_scaledSigmaA.max() > 0.0f) brdf *= std::exp(_scaledSigmaA*(-1.0f/event.wo.z() - 1.0f/event.wi.z())); return brdf; } else { return Vec3f(0.0f); } }
bool RoughConductorBsdf::sample(SurfaceScatterEvent &event) const { if (!event.requestedLobe.test(BsdfLobes::GlossyReflectionLobe)) return false; if (event.wi.z() <= 0.0f) return false; // TODO Re-enable this? //float sampleRoughness = (1.2f - 0.2f*std::sqrt(std::abs(event.wi.z())))*_roughness; float roughness = (*_roughness)[*event.info].x(); float sampleRoughness = roughness; float alpha = Microfacet::roughnessToAlpha(_distribution, roughness); float sampleAlpha = Microfacet::roughnessToAlpha(_distribution, sampleRoughness); Vec3f m = Microfacet::sample(_distribution, sampleAlpha, event.sampler->next2D(BsdfSample)); float wiDotM = event.wi.dot(m); event.wo = 2.0f*wiDotM*m - event.wi; if (wiDotM <= 0.0f || event.wo.z() <= 0.0f) return false; float G = Microfacet::G(_distribution, alpha, event.wi, event.wo, m); float D = Microfacet::D(_distribution, alpha, m); float mPdf = Microfacet::pdf(_distribution, sampleAlpha, m); float pdf = mPdf*0.25f/wiDotM; float weight = wiDotM*G*D/(event.wi.z()*mPdf); Vec3f F = Fresnel::conductorReflectance(_eta, _k, wiDotM); event.pdf = pdf; event.weight = albedo(event.info)*(F*weight); event.sampledLobe = BsdfLobes::GlossyReflectionLobe; return true; }
Vec3f ConductorBsdf::eval(const SurfaceScatterEvent &event) const { bool evalR = event.requestedLobe.test(BsdfLobes::SpecularReflectionLobe); if (evalR && checkReflectionConstraint(event.wi, event.wo)) return albedo(event.info)*Fresnel::conductorReflectance(_eta, _k, event.wi.z()); else return Vec3f(0.0f); }
Vec3f LambertBsdf::eval(const SurfaceScatterEvent &event) const { if (!event.requestedLobe.test(BsdfLobes::DiffuseReflectionLobe)) return Vec3f(0.0f); if (event.wi.z() <= 0.0f || event.wo.z() <= 0.0f) return Vec3f(0.0f); return albedo(event.info)*INV_PI*event.wo.z(); }
bool ConductorBsdf::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.weight = albedo(event.info)*Fresnel::conductorReflectance(_eta, _k, event.wi.z()); event.sampledLobe = BsdfLobes::SpecularReflectionLobe; return true; }
bool LambertBsdf::sample(SurfaceScatterEvent &event) const { if (!event.requestedLobe.test(BsdfLobes::DiffuseReflectionLobe)) return false; if (event.wi.z() <= 0.0f) return false; event.wo = SampleWarp::cosineHemisphere(event.sampler->next2D()); event.pdf = SampleWarp::cosineHemispherePdf(event.wo); event.weight = albedo(event.info); event.sampledLobe = BsdfLobes::DiffuseReflectionLobe; return true; }
Vec3f RoughWireBcsdf::eval(const SurfaceScatterEvent &event) const { if (!event.requestedLobe.test(BsdfLobes::GlossyLobe) || event.wo.z() == 0.0f) return Vec3f(0.0f); float sinThetaI = event.wi.y(); float sinThetaO = event.wo.y(); float cosThetaI = trigInverse(sinThetaI); float cosThetaO = trigInverse(sinThetaO); float cosPhi = event.wo.z()/std::sqrt(event.wo.x()*event.wo.x() + event.wo.z()*event.wo.z()); Vec3f attenuation = albedo(event.info)*Fresnel::conductorReflectance(_eta, _k, trigHalfAngle(event.wi.dot(event.wo))); return attenuation*N(cosPhi)*M(_v, sinThetaI, sinThetaO, cosThetaI, cosThetaO); }
bool PlasticBsdf::sample(SurfaceScatterEvent &event) const { if (event.wi.z() <= 0.0f) return false; bool sampleR = event.requestedLobe.test(BsdfLobes::SpecularReflectionLobe); bool sampleT = event.requestedLobe.test(BsdfLobes::DiffuseReflectionLobe); const Vec3f &wi = event.wi; float eta = 1.0f/_ior; float Fi = Fresnel::dielectricReflectance(eta, wi.z()); float substrateWeight = _avgTransmittance*(1.0f - Fi); float specularWeight = Fi; float specularProbability; if (sampleR && sampleT) specularProbability = specularWeight/(specularWeight + substrateWeight); else if (sampleR) specularProbability = 1.0f; else if (sampleT) specularProbability = 0.0f; else return false; if (sampleR && event.sampler->nextBoolean(specularProbability)) { event.wo = Vec3f(-wi.x(), -wi.y(), wi.z()); event.pdf = specularProbability; event.weight = Vec3f(Fi/specularProbability); event.sampledLobe = BsdfLobes::SpecularReflectionLobe; } else { Vec3f wo(SampleWarp::cosineHemisphere(event.sampler->next2D())); float Fo = Fresnel::dielectricReflectance(eta, wo.z()); Vec3f diffuseAlbedo = albedo(event.info); event.wo = wo; event.weight = ((1.0f - Fi)*(1.0f - Fo)*eta*eta)*(diffuseAlbedo/(1.0f - diffuseAlbedo*_diffuseFresnel)); if (_scaledSigmaA.max() > 0.0f) event.weight *= std::exp(_scaledSigmaA*(-1.0f/event.wo.z() - 1.0f/event.wi.z())); event.pdf = SampleWarp::cosineHemispherePdf(event.wo)*(1.0f - specularProbability); event.weight /= 1.0f - specularProbability; event.sampledLobe = BsdfLobes::DiffuseReflectionLobe; } return true; }
Vec3f RoughConductorBsdf::eval(const SurfaceScatterEvent &event) const { if (!event.requestedLobe.test(BsdfLobes::GlossyReflectionLobe)) return Vec3f(0.0f); if (event.wi.z() <= 0.0f || event.wo.z() <= 0.0f) return Vec3f(0.0f); float roughness = (*_roughness)[*event.info].x(); float alpha = Microfacet::roughnessToAlpha(_distribution, roughness); Vec3f hr = (event.wi + event.wo).normalized(); float cosThetaM = event.wi.dot(hr); Vec3f F = Fresnel::conductorReflectance(_eta, _k, cosThetaM); float G = Microfacet::G(_distribution, alpha, event.wi, event.wo, hr); float D = Microfacet::D(_distribution, alpha, hr); float fr = (G*D*0.25f)/event.wi.z(); return albedo(event.info)*(F*fr); }
Vec3f PhongBsdf::eval(const SurfaceScatterEvent &event) const { bool evalGlossy = event.requestedLobe.test(BsdfLobes::GlossyReflectionLobe); bool evalDiffuse = event.requestedLobe.test(BsdfLobes::DiffuseReflectionLobe); if (!evalGlossy && !evalDiffuse) return Vec3f(0.0f); if (event.wi.z() <= 0.0f || event.wo.z() <= 0.0f) return Vec3f(0.0f); float result = 0.0f; if (evalDiffuse) result += _diffuseRatio*INV_PI; if (evalGlossy) { float cosTheta = Vec3f(-event.wi.x(), -event.wi.y(), event.wi.z()).dot(event.wo); if (cosTheta > 0.0f) result += std::pow(cosTheta, _exponent)*_brdfFactor*(1.0f - _diffuseRatio); } return albedo(event.info)*event.wo.z()*result; }
Vec3f OrenNayarBsdf::eval(const SurfaceScatterEvent &event) const { if (!event.requestedLobe.test(BsdfLobes::DiffuseReflectionLobe)) return Vec3f(0.0f); if (event.wi.z() <= 0.0f || event.wo.z() <= 0.0f) return Vec3f(0.0f); const Vec3f &wi = event.wi; const Vec3f &wo = event.wo; float thetaR = std::acos(event.wo.z()); float thetaI = std::acos(event.wi.z()); float alpha = max(thetaR, thetaI); float beta = min(thetaR, thetaI); float sinAlpha = std::sin(alpha); float denom = (wi.x()*wi.x() + wi.y()*wi.y())*(wo.x()*wo.x() + wo.y()*wo.y()); float cosDeltaPhi; if (denom == 0.0f) cosDeltaPhi = 1.0f; else cosDeltaPhi = (wi.x()*wo.x() + wi.y()*wo.y())/std::sqrt(denom); const float RoughnessToSigma = 1.0f/std::sqrt(2.0f); float sigma = RoughnessToSigma*(*_roughness)[*event.info].x(); float sigmaSq = sigma*sigma; float C1 = 1.0f - 0.5f*sigmaSq/(sigmaSq + 0.33f); float C2 = 0.45f*sigmaSq/(sigmaSq + 0.09f); if (cosDeltaPhi >= 0.0f) C2 *= sinAlpha; else C2 *= sinAlpha - cube((2.0f*INV_PI)*beta); float C3 = 0.125f*(sigmaSq/(sigmaSq + 0.09f))*sqr((4.0f*INV_PI*INV_PI)*alpha*beta); float fr1 = (C1 + cosDeltaPhi*C2*std::tan(beta) + (1.0f - std::abs(cosDeltaPhi))*C3*std::tan(0.5f*(alpha + beta))); float fr2 = 0.17f*sigmaSq/(sigmaSq + 0.13f)*(1.0f - cosDeltaPhi*sqr((2.0f*INV_PI)*beta)); Vec3f diffuseAlbedo = albedo(event.info); return (diffuseAlbedo*fr1 + diffuseAlbedo*diffuseAlbedo*fr2)*wo.z()*INV_PI; }
void Vegetation::output (Log& log) const { output_value (N (), "N", log); output_value (N_fixated (), "N_fixated", log); output_value (LAI (), "LAI", log); output_value (height (), "height", log); output_value (cover (), "cover", log); output_value (LAIvsH (), "LAIvsH", log); output_value (HvsLAI (), "HvsLAI", log); output_value (ACExt_PAR (), "ACExt_PAR", log); output_value (ACRef_PAR (), "ACRef_PAR", log); output_value (ACExt_NIR (), "ACExt_NIR", log); output_value (ACRef_NIR (), "ACRef_NIR", log); output_value (ARExt (), "ARExt", log); output_value (EpFactorDry (), "EpFactorDry", log); output_value (EpFactorWet (), "EpFactorWet", log); output_value (albedo (), "albedo", log); output_value (interception_capacity (), "interception_capacity", log); output_value (shadow_stomata_conductance (), "shadow_stomata_conductance", log); output_value (sunlit_stomata_conductance (), "sunlit_stomata_conductance", log); }
bool RoughWireBcsdf::sample(SurfaceScatterEvent &event) const { if (!event.requestedLobe.test(BsdfLobes::GlossyLobe)) return false; float xi1 = event.sampler->next1D(); Vec2f xi23 = event.sampler->next2D(); float sinThetaI = event.wi.y(); float cosThetaI = trigInverse(sinThetaI); float sinPhi = sampleN(xi1); float sinThetaO = sampleM(_v, sinThetaI, cosThetaI, xi23.x(), xi23.y()); float cosPhi = trigInverse(sinPhi); float cosThetaO = trigInverse(sinThetaO); event.wo = Vec3f(sinPhi*cosThetaO, sinThetaO, cosPhi*cosThetaO); event.pdf = N(cosPhi)*M(_v, sinThetaI, sinThetaO, cosThetaI, cosThetaO); event.weight = albedo(event.info)*Fresnel::conductorReflectance(_eta, _k, trigHalfAngle(event.wi.dot(event.wo))); event.sampledLobe = BsdfLobes::GlossyLobe; return true; }
Vec3f MixedBsdf::eval(const SurfaceScatterEvent &event) const { float ratio = (*_ratio)[*event.info].x(); return albedo(event.info)*(_bsdf0->eval(event)*ratio + _bsdf1->eval(event)*(1.0f - ratio)); }