00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "cooktorrance.h"
00025 #include "color.h"
00026 #include "spectrum.h"
00027 #include "mc.h"
00028 #include "sampling.h"
00029 #include "microfacetdistribution.h"
00030 #include "fresnel.h"
00031 #include <stdarg.h>
00032
00033 using namespace lux;
00034
00035 CookTorrance::CookTorrance(const SWCSpectrum &kd, u_int nl,
00036 const SWCSpectrum *ks,
00037 MicrofacetDistribution **dist, Fresnel **fres) : BxDF(BxDFType(BSDF_REFLECTION | BSDF_SPECULAR)) {
00038 KD = kd;
00039 KS = ks;
00040 nLobes = nl;
00041 distribution = dist;
00042 fresnel = fres;
00043 }
00044
00045 SWCSpectrum CookTorrance::f(const Vector &wo, const Vector &wi) const {
00046 SWCSpectrum ret = KD * INV_PI;
00047
00048 float cosThetaO = fabsf(CosTheta(wo));
00049 float cosThetaI = fabsf(CosTheta(wi));
00050 Vector wh = Normalize(wi + wo);
00051 float cosThetaH = Dot(wi, wh);
00052 float cG = G(wo, wi, wh);
00053
00054 for (u_int i = 0; i < nLobes; i++) {
00055
00056
00057 ret += KS[i] * distribution[i]->D(wh) * cG * fresnel[i]->Evaluate(cosThetaH) / (M_PI * cosThetaI * cosThetaO);
00058 }
00059 return ret;
00060 }
00061
00062 float CookTorrance::G(const Vector &wo, const Vector &wi, const Vector &wh) const {
00063 float NdotWh = fabsf(CosTheta(wh));
00064 float NdotWo = fabsf(CosTheta(wo));
00065 float NdotWi = fabsf(CosTheta(wi));
00066 float WOdotWh = AbsDot(wo, wh);
00067 return min(1.f, min((2.f * NdotWh * NdotWo / WOdotWh), (2.f * NdotWh * NdotWi / WOdotWh)));
00068 }
00069
00070 SWCSpectrum CookTorrance::Sample_f(const Vector &wo, Vector *wi, float u1, float u2, float *pdf, float *pdfBack) const {
00071
00072 u_int comp = lux::random::uintValue() % (nLobes+1);
00073
00074 if (comp == nLobes) {
00075
00076 *wi = CosineSampleHemisphere(u1, u2);
00077 if (wo.z < 0.)
00078 wi->z *= -1.f;
00079 }
00080 else {
00081
00082 distribution[comp]->Sample_f(wo, wi, u1, u2, pdf);
00083 }
00084 *pdf = Pdf(wo, *wi);
00085 if (*pdf == 0.f) {
00086 if (pdfBack)
00087 *pdfBack = 0.f;
00088 return SWCSpectrum(0.f);
00089 }
00090 if (pdfBack)
00091 *pdfBack = Pdf(*wi, wo);
00092
00093 return f(wo, *wi);
00094 }
00095
00096 float CookTorrance::Pdf(const Vector &wo, const Vector &wi) const {
00097 if (!SameHemisphere(wo, wi))
00098 return 0.f;
00099
00100
00101 float pdfSum = fabsf(wi.z) * INV_PI;
00102
00103 for (u_int i = 0; i < nLobes; ++i) {
00104 pdfSum += distribution[i]->Pdf(wo, wi);
00105 }
00106 return pdfSum / (1.f + nLobes);
00107 }
00108