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 "light.h"
00025 #include "randomgen.h"
00026 #include "mc.h"
00027 #include "shape.h"
00028 #include "context.h"
00029 #include "paramset.h"
00030 #include "rgbillum.h"
00031 #include "blackbodyspd.h"
00032 #include "reflection/bxdf.h"
00033 #include "reflection/bxdf/lambertian.h"
00034 #include "dynload.h"
00035
00036 using namespace lux;
00037
00038 class GonioAreaBxDF : public BxDF {
00039 public:
00040 GonioAreaBxDF(const SampleableSphericalFunction *func) :
00041 BxDF(BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE)), sf(func) {}
00042 virtual ~GonioAreaBxDF() { }
00043 virtual void f(const TsPack *tspack, const Vector &wo, const Vector &wi, SWCSpectrum *const F) const {
00044 *F += SWCSpectrum(tspack, sf->f(wi));
00045 }
00046 private:
00047 const SampleableSphericalFunction *sf;
00048 };
00049
00050
00051 AreaLight::AreaLight(const Transform &light2world,
00052 boost::shared_ptr<Texture<SWCSpectrum> > le,
00053 float g, float pow, float e,
00054 SampleableSphericalFunction *ssf,
00055 int ns, const boost::shared_ptr<Primitive> &p)
00056 : Light(light2world, ns) {
00057 Le = le;
00058 gain = g;
00059 power = pow;
00060 efficacy = e;
00061 func = ssf;
00062
00063 if (p->CanIntersect() && p->CanSample())
00064 prim = p;
00065 else {
00066
00067 vector<boost::shared_ptr<Primitive> > refinedPrims;
00068 PrimitiveRefinementHints refineHints(true);
00069 p->Refine(refinedPrims, refineHints, p);
00070 if (refinedPrims.size() == 1) prim = refinedPrims[0];
00071 else {
00072 prim = boost::shared_ptr<Primitive>(new PrimitiveSet(refinedPrims));
00073 }
00074 }
00075 area = prim->Area();
00076 Le->SetIlluminant();
00077 Le->SetPower(power*efficacy, area);
00078 }
00079 AreaLight::~AreaLight() {
00080 if(func)
00081 delete func;
00082 }
00083
00084 SWCSpectrum AreaLight::Sample_L(const TsPack *tspack, const Point &p,
00085 const Normal &n, float u1, float u2, float u3,
00086 Vector *wi, float *pdf,
00087 VisibilityTester *visibility) const {
00088 DifferentialGeometry dg;
00089 dg.time = tspack->time;
00090 prim->Sample(p, u1, u2, u3, &dg);
00091 *wi = Normalize(dg.p - p);
00092 *pdf = prim->Pdf(p, *wi);
00093 visibility->SetSegment(p, dg.p, tspack->time);
00094 return L(tspack, dg, -*wi);
00095 }
00096 float AreaLight::Pdf(const Point &p, const Normal &N,
00097 const Vector &wi) const {
00098 return prim->Pdf(p, wi);
00099 }
00100 float AreaLight::Pdf(const Point &p, const Normal &N,
00101 const Point &po, const Normal &ns) const
00102 {
00103 return prim->Pdf(p, po);
00104 }
00105 SWCSpectrum AreaLight::Sample_L(const TsPack *tspack, const Point &P,
00106 float u1, float u2, float u3, Vector *wo, float *pdf,
00107 VisibilityTester *visibility) const {
00108 DifferentialGeometry dg;
00109 dg.time = tspack->time;
00110 prim->Sample(P, u1, u2, u3, &dg);
00111 *wo = Normalize(dg.p - P);
00112 *pdf = prim->Pdf(P, *wo);
00113 visibility->SetSegment(P, dg.p, tspack->time);
00114 return L(tspack, dg, -*wo);
00115 }
00116 SWCSpectrum AreaLight::Sample_L(const TsPack *tspack, const Scene *scene, float u1,
00117 float u2, float u3, float u4,
00118 Ray *ray, float *pdf) const {
00119 DifferentialGeometry dg;
00120 dg.time = tspack->time;
00121 prim->Sample(u1, u2, tspack->rng->floatValue(), &dg);
00122 ray->o = dg.p;
00123 ray->d = UniformSampleSphere(u3, u4);
00124 if (Dot(ray->d, dg.nn) < 0.) ray->d *= -1;
00125 *pdf = prim->Pdf(ray->o) * INV_TWOPI;
00126 return L(tspack, dg, ray->d);
00127 }
00128 float AreaLight::Pdf(const Point &P, const Vector &w) const {
00129 return prim->Pdf(P, w);
00130 }
00131 bool AreaLight::Sample_L(const TsPack *tspack, const Scene *scene, float u1, float u2, float u3, BSDF **bsdf, float *pdf, SWCSpectrum *Le) const
00132 {
00133 DifferentialGeometry dg;
00134 dg.time = tspack->time;
00135 prim->Sample(u1, u2, u3, &dg);
00136 if(func)
00137 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, dg.nn,
00138 BSDF_ALLOC(tspack, GonioAreaBxDF)(func));
00139 else
00140 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, dg.nn,
00141 BSDF_ALLOC(tspack, Lambertian)(SWCSpectrum(1.f)));
00142 *pdf = prim->Pdf(dg.p);
00143 if (*pdf > 0.f) {
00144 *Le = this->Le->Evaluate(tspack, dg) * gain * M_PI;
00145 return true;
00146 }
00147 *Le = 0.f;
00148 return false;
00149 }
00150 bool AreaLight::Sample_L(const TsPack *tspack, const Scene *scene, const Point &p, const Normal &n,
00151 float u1, float u2, float u3, BSDF **bsdf, float *pdf, float *pdfDirect,
00152 VisibilityTester *visibility, SWCSpectrum *Le) const
00153 {
00154 DifferentialGeometry dg;
00155 dg.time = tspack->time;
00156 prim->Sample(p, u1, u2, u3, &dg);
00157 Vector wo(Normalize(dg.p - p));
00158 *pdf = prim->Pdf(dg.p);
00159 *pdfDirect = prim->Pdf(p, dg.p);
00160 if (*pdfDirect > 0.f) {
00161 if(func)
00162 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, dg.nn,
00163 BSDF_ALLOC(tspack, GonioAreaBxDF)(func));
00164 else
00165 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, dg.nn,
00166 BSDF_ALLOC(tspack, Lambertian)(SWCSpectrum(1.f)));
00167 visibility->SetSegment(p, dg.p, tspack->time);
00168 *Le = this->Le->Evaluate(tspack, dg) * gain * M_PI;
00169 return true;
00170 }
00171 *Le = 0.f;
00172 return false;
00173 }
00174 SWCSpectrum AreaLight::L(const TsPack *tspack, const Ray &ray, const DifferentialGeometry &dg, const Normal &n, BSDF **bsdf, float *pdf, float *pdfDirect) const
00175 {
00176 if(func)
00177 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, dg.nn,
00178 BSDF_ALLOC(tspack, GonioAreaBxDF)(func));
00179 else
00180 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, dg.nn,
00181 BSDF_ALLOC(tspack, Lambertian)(SWCSpectrum(1.f)));
00182 *pdf = prim->Pdf(dg.p);
00183 *pdfDirect = prim->Pdf(ray.o, dg.p);
00184 return L(tspack, dg, -ray.d);
00185 }
00186
00187 class HemiSphereSphericalFunction : public SphericalFunction {
00188 public:
00189 HemiSphereSphericalFunction(const boost::shared_ptr<const SphericalFunction> aSF) : sf(aSF) {}
00190 RGBColor f(float phi, float theta) const {
00191 return theta > 0.f ? sf->f(phi, theta) : 0.f;
00192 }
00193 private:
00194 const boost::shared_ptr<const SphericalFunction> sf;
00195 };
00196
00197 AreaLight* AreaLight::CreateAreaLight(const Transform &light2world, const ParamSet ¶mSet, const TextureParams &tp,
00198 const boost::shared_ptr<Primitive> &prim) {
00199 boost::shared_ptr<Texture<SWCSpectrum> > L = tp.GetSWCSpectrumTexture("L", RGBColor(1.f));
00200
00201 float g = paramSet.FindOneFloat("gain", 1.f);
00202 float p = paramSet.FindOneFloat("power", 100.f);
00203 float e = paramSet.FindOneFloat("efficacy", 17.f);
00204
00205 const SphericalFunction *sf = CreateSphericalFunction(paramSet, tp);
00206 SampleableSphericalFunction *ssf = NULL;
00207 if (sf) {
00208 sf = new HemiSphereSphericalFunction(boost::shared_ptr<const SphericalFunction>(sf));
00209 ssf = new SampleableSphericalFunction(boost::shared_ptr<const SphericalFunction>(sf));
00210 }
00211
00212 int nSamples = paramSet.FindOneInt("nsamples", 1);
00213 return new AreaLight(light2world, L, g, p, e, ssf, nSamples, prim);
00214 }
00215
00216 static DynamicLoader::RegisterAreaLight<AreaLight> r("area");
00217