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 "bxdf.h"
00025 #include "color.h"
00026 #include "spectrum.h"
00027 #include "mc.h"
00028 #include "sampling.h"
00029 #include <stdarg.h>
00030
00031 using namespace lux;
00032
00033
00034 SWCSpectrum BRDFToBTDF::f(const Vector &wo,
00035 const Vector &wi) const {
00036 return brdf->f(wo, otherHemisphere(wi));
00037 }
00038 SWCSpectrum BRDFToBTDF::Sample_f(const Vector &wo, Vector *wi,
00039 float u1, float u2, float *pdf, float *pdfBack) const {
00040 SWCSpectrum f = brdf->Sample_f(wo, wi, u1, u2, pdf, pdfBack);
00041 *wi = otherHemisphere(*wi);
00042 return f;
00043 }
00044
00045 SWCSpectrum BxDF::Sample_f(const Vector &wo, Vector *wi,
00046 float u1, float u2, float *pdf, float *pdfBack) const {
00047
00048 *wi = CosineSampleHemisphere(u1, u2);
00049 if (wo.z < 0.) wi->z *= -1.f;
00050 *pdf = Pdf(wo, *wi);
00051 if (pdfBack)
00052 *pdfBack = Pdf(*wi, wo);
00053 return f(wo, *wi);
00054 }
00055 float BxDF::Pdf(const Vector &wo, const Vector &wi) const {
00056 return
00057 SameHemisphere(wo, wi) ? fabsf(wi.z) * INV_PI : 0.f;
00058 }
00059 float BRDFToBTDF::Pdf(const Vector &wo,
00060 const Vector &wi) const {
00061 return brdf->Pdf(wo, otherHemisphere(wi));
00062 }
00063
00064 SWCSpectrum BxDF::rho(const Vector &w, int nSamples,
00065 float *samples) const {
00066 if (!samples) {
00067 samples =
00068 (float *)alloca(2 * nSamples * sizeof(float));
00069 LatinHypercube(samples, nSamples, 2);
00070 }
00071 SWCSpectrum r = 0.;
00072 for (int i = 0; i < nSamples; ++i) {
00073
00074 Vector wi;
00075 float pdf = 0.f;
00076 SWCSpectrum f =
00077 Sample_f(w, &wi, samples[2*i], samples[2*i+1], &pdf);
00078 if (pdf > 0.) r += f * fabsf(wi.z) / pdf;
00079 }
00080 return r / nSamples;
00081 }
00082 SWCSpectrum BxDF::rho(int nSamples, float *samples) const {
00083 if (!samples) {
00084 samples =
00085 (float *)alloca(4 * nSamples * sizeof(float));
00086 LatinHypercube(samples, nSamples, 4);
00087 }
00088 SWCSpectrum r = 0.;
00089 for (int i = 0; i < nSamples; ++i) {
00090
00091 Vector wo, wi;
00092 wo = UniformSampleHemisphere(samples[4*i], samples[4*i+1]);
00093 float pdf_o = INV_TWOPI, pdf_i = 0.f;
00094 SWCSpectrum f =
00095 Sample_f(wo, &wi, samples[4*i+2], samples[4*i+3],
00096 &pdf_i);
00097 if (pdf_i > 0.)
00098 r += f * fabsf(wi.z * wo.z) / (pdf_o * pdf_i);
00099 }
00100 return r / (M_PI*nSamples);
00101 }
00102
00103 SWCSpectrum BSDF::Sample_f(const Vector &wo, Vector *wi, BxDFType flags,
00104 BxDFType *sampledType) const {
00105 float pdf;
00106 SWCSpectrum f = Sample_f(wo, wi, lux::random::floatValue(), lux::random::floatValue(),
00107 lux::random::floatValue(), &pdf, flags, sampledType);
00108 if (!f.Black() && pdf > 0.) f /= pdf;
00109 return f;
00110 }
00111 SWCSpectrum BSDF::Sample_f(const Vector &woW, Vector *wiW,
00112 float u1, float u2, float u3, float *pdf,
00113 BxDFType flags, BxDFType *sampledType, float *pdfBack) const {
00114
00115 int matchingComps = NumComponents(flags);
00116 if (matchingComps == 0) {
00117 *pdf = 0.f;
00118 if (pdfBack)
00119 *pdfBack = 0.f;
00120 return SWCSpectrum(0.f);
00121 }
00122 int which = min(Floor2Int(u3 * matchingComps),
00123 matchingComps-1);
00124 BxDF *bxdf = NULL;
00125 int count = which;
00126 for (int i = 0; i < nBxDFs; ++i)
00127 if (bxdfs[i]->MatchesFlags(flags))
00128 if (count-- == 0) {
00129 bxdf = bxdfs[i];
00130 break;
00131 }
00132 BOOST_ASSERT(bxdf);
00133
00134 Vector wi;
00135 Vector wo = WorldToLocal(woW);
00136 *pdf = 0.f;
00137 if (pdfBack)
00138 *pdfBack = 0.f;
00139 SWCSpectrum f = bxdf->Sample_f(wo, &wi, u1, u2, pdf, pdfBack);
00140 if (*pdf == 0.f) return 0.f;
00141 if (sampledType) *sampledType = bxdf->type;
00142 *wiW = LocalToWorld(wi);
00143
00144 if (!(bxdf->type & BSDF_SPECULAR) && matchingComps > 1) {
00145 for (int i = 0; i < nBxDFs; ++i) {
00146 if (bxdfs[i] != bxdf &&
00147 bxdfs[i]->MatchesFlags(flags)) {
00148 *pdf += bxdfs[i]->Pdf(wo, wi);
00149 if (pdfBack)
00150 *pdfBack += bxdfs[i]->Pdf(wi, wo);
00151 }
00152 }
00153 }
00154 if (matchingComps > 1) {
00155 *pdf /= matchingComps;
00156 if (pdfBack)
00157 *pdfBack /= matchingComps;
00158 }
00159
00160 if (!(bxdf->type & BSDF_SPECULAR)) {
00161 f = 0.;
00162 if (Dot(*wiW, ng) * Dot(woW, ng) > 0)
00163
00164 flags = BxDFType(flags & ~BSDF_TRANSMISSION);
00165 else
00166
00167 flags = BxDFType(flags & ~BSDF_REFLECTION);
00168 for (int i = 0; i < nBxDFs; ++i)
00169 if (bxdfs[i]->MatchesFlags(flags))
00170 f += bxdfs[i]->f(wo, wi);
00171 }
00172 return f;
00173 }
00174 float BSDF::Pdf(const Vector &woW, const Vector &wiW,
00175 BxDFType flags) const {
00176 if (nBxDFs == 0.) return 0.;
00177 Vector wo = WorldToLocal(woW), wi = WorldToLocal(wiW);
00178 float pdf = 0.f;
00179 int matchingComps = 0;
00180 for (int i = 0; i < nBxDFs; ++i)
00181 if (bxdfs[i]->MatchesFlags(flags)) {
00182 ++matchingComps;
00183 pdf += bxdfs[i]->Pdf(wo, wi);
00184 }
00185 return matchingComps > 0 ? pdf / matchingComps : 0.f;
00186 }
00187 BSDF::BSDF(const DifferentialGeometry &dg,
00188 const Normal &ngeom, float e)
00189 : dgShading(dg), eta(e) {
00190 ng = ngeom;
00191 nn = dgShading.nn;
00192 sn = Normalize(dgShading.dpdu);
00193 tn = Cross(nn, sn);
00194 nBxDFs = 0;
00195 }
00196 SWCSpectrum BSDF::f(const Vector &woW,
00197 const Vector &wiW, BxDFType flags) const {
00198 Vector wi = WorldToLocal(wiW), wo = WorldToLocal(woW);
00199 if (Dot(wiW, ng) * Dot(woW, ng) > 0)
00200
00201 flags = BxDFType(flags & ~BSDF_TRANSMISSION);
00202 else
00203
00204 flags = BxDFType(flags & ~BSDF_REFLECTION);
00205 SWCSpectrum f = 0.;
00206 for (int i = 0; i < nBxDFs; ++i)
00207 if (bxdfs[i]->MatchesFlags(flags))
00208 f += bxdfs[i]->f(wo, wi);
00209 return f;
00210 }
00211 SWCSpectrum BSDF::rho(BxDFType flags) const {
00212 SWCSpectrum ret(0.);
00213 for (int i = 0; i < nBxDFs; ++i)
00214 if (bxdfs[i]->MatchesFlags(flags))
00215 ret += bxdfs[i]->rho();
00216 return ret;
00217 }
00218 SWCSpectrum BSDF::rho(const Vector &wo, BxDFType flags) const {
00219 SWCSpectrum ret(0.);
00220 for (int i = 0; i < nBxDFs; ++i)
00221 if (bxdfs[i]->MatchesFlags(flags))
00222 ret += bxdfs[i]->rho(wo);
00223 return ret;
00224 }
00225
00226 boost::thread_specific_ptr<MemoryArena> BSDF::arena;
00227