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 "point.h"
00025 #include "mc.h"
00026 #include "reflection/bxdf.h"
00027 #include "reflection/bxdf/lambertian.h"
00028 #include "paramset.h"
00029 #include "dynload.h"
00030
00031 using namespace lux;
00032
00033 class GonioBxDF : public BxDF {
00034 public:
00035 GonioBxDF(const Normal &ns, const Vector &du, const Vector &dv, const SampleableSphericalFunction *func) :
00036 BxDF(BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE)), x(du), y(dv), z(Vector(ns)), sf(func) {}
00037 virtual ~GonioBxDF() { }
00038 virtual void f(const TsPack *tspack, const Vector &wo, const Vector &wi, SWCSpectrum *const F) const {
00039
00040 const Vector wL(wi.x * x.x + wi.y * y.x + wi.z * z.x,
00041 wi.x * x.y + wi.y * y.y + wi.z * z.y,
00042 wi.x * x.z + wi.y * y.z + wi.z * z.z);
00043 *F += SWCSpectrum(tspack, sf->f(wL));
00044 }
00045 private:
00046 Vector x, y, z;
00047 const SampleableSphericalFunction *sf;
00048 };
00049
00050
00051 PointLight::PointLight(
00052 const Transform &light2world,
00053 const boost::shared_ptr< Texture<SWCSpectrum> > L,
00054 float g,
00055 SampleableSphericalFunction *ssf)
00056 : Light(light2world) {
00057 lightPos = LightToWorld(Point(0,0,0));
00058 Lbase = L;
00059 Lbase->SetIlluminant();
00060 gain = g;
00061 func = ssf;
00062 }
00063 PointLight::~PointLight() {
00064 if(func)
00065 delete func;
00066 }
00067 SWCSpectrum PointLight::Power(const TsPack *tspack, const Scene *) const {
00068 return Lbase->Evaluate(tspack, dummydg) * gain * 4.f * M_PI * (func ? func->Average_f() : 1.f);
00069 }
00070 SWCSpectrum PointLight::Sample_L(const TsPack *tspack, const Point &P, float u1, float u2,
00071 float u3, Vector *wo, float *pdf,
00072 VisibilityTester *visibility) const {
00073 *wo = Normalize(lightPos - P);
00074 *pdf = 1.f;
00075 visibility->SetSegment(P, lightPos, tspack->time);
00076 return L(tspack, WorldToLight(-*wo)) / DistanceSquared(lightPos, P);
00077 }
00078 SWCSpectrum PointLight::Sample_L(const TsPack *tspack, const Scene *scene, float u1, float u2,
00079 float u3, float u4, Ray *ray, float *pdf) const {
00080 ray->o = lightPos;
00081 if(func) {
00082 Vector w;
00083 RGBColor f = func->Sample_f(u1, u2, &w, pdf);
00084 ray->d = LightToWorld(w);
00085 return Lbase->Evaluate(tspack, dummydg) * gain * SWCSpectrum(tspack, f);
00086 }
00087 else {
00088 ray->d = UniformSampleSphere(u1, u2);
00089 *pdf = UniformSpherePdf();
00090 return Lbase->Evaluate(tspack, dummydg) * gain;
00091 }
00092 }
00093 float PointLight::Pdf(const Point &, const Vector &) const {
00094 return 0.;
00095 }
00096 float PointLight::Pdf(const Point &p, const Normal &n,
00097 const Point &po, const Normal &ns) const
00098 {
00099 return AbsDot(Normalize(p - po), ns) / DistanceSquared(p, po);
00100 }
00101 SWCSpectrum PointLight::L(const TsPack *tspack, const Vector &w) const {
00102 return Lbase->Evaluate(tspack, dummydg) * SWCSpectrum(tspack, gain * (func ? func->f(w) : 1.f));
00103 }
00104 bool PointLight::Sample_L(const TsPack *tspack, const Scene *scene, float u1, float u2, float u3, BSDF **bsdf, float *pdf, SWCSpectrum *Le) const
00105 {
00106 Vector w;
00107 if(func) {
00108 func->Sample_f(u1, u2, &w, pdf);
00109 w = LightToWorld(w);
00110 }
00111 else {
00112 w = UniformSampleSphere(u1, u2);
00113 *pdf = UniformSpherePdf();
00114 }
00115 Vector dpdu, dpdv;
00116 CoordinateSystem(w, &dpdu, &dpdv);
00117 const Normal ns(w);
00118 DifferentialGeometry dg(lightPos, ns, dpdu, dpdv, Normal(0, 0, 0), Normal(0, 0, 0), 0, 0, NULL);
00119 if(func)
00120 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, ns,
00121 BSDF_ALLOC(tspack, GonioBxDF)(WorldToLight(ns), WorldToLight(dpdu), WorldToLight(dpdv), func));
00122 else
00123 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, ns,
00124 BSDF_ALLOC(tspack, Lambertian)(1.f));
00125 *Le = Lbase->Evaluate(tspack, dummydg) * gain;
00126 return true;
00127 }
00128 bool PointLight::Sample_L(const TsPack *tspack, const Scene *scene, const Point &p, const Normal &n,
00129 float u1, float u2, float u3, BSDF **bsdf, float *pdf, float *pdfDirect,
00130 VisibilityTester *visibility, SWCSpectrum *Le) const
00131 {
00132 const Vector w(p - lightPos);
00133 Normal ns = Normal(Normalize(w));
00134 *pdfDirect = 1.f;
00135 if(func)
00136 *pdf = func->Pdf(WorldToLight(w));
00137 else
00138 *pdf = UniformSpherePdf();
00139 Vector dpdu, dpdv;
00140 CoordinateSystem(Vector(ns), &dpdu, &dpdv);
00141 DifferentialGeometry dg(lightPos, ns, dpdu, dpdv, Normal(0, 0, 0), Normal(0, 0, 0), 0, 0, NULL);
00142 if(func)
00143 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, ns,
00144 BSDF_ALLOC(tspack, GonioBxDF)(WorldToLight(ns), WorldToLight(dpdu), WorldToLight(dpdv), func));
00145 else
00146 *bsdf = BSDF_ALLOC(tspack, SingleBSDF)(dg, ns,
00147 BSDF_ALLOC(tspack, Lambertian)(1.f));
00148 visibility->SetSegment(p, lightPos, tspack->time);
00149 *Le = Lbase->Evaluate(tspack, dummydg) * gain;
00150 return true;
00151 }
00152 SWCSpectrum PointLight::Le(const TsPack *tspack, const Scene *scene, const Ray &r,
00153 const Normal &n, BSDF **bsdf, float *pdf, float *pdfDirect) const
00154 {
00155 return SWCSpectrum(0.f);
00156 }
00157 Light* PointLight::CreateLight(const Transform &light2world,
00158 const ParamSet ¶mSet, const TextureParams &tp) {
00159 boost::shared_ptr<Texture<SWCSpectrum> > L = tp.GetSWCSpectrumTexture("L", RGBColor(1.f));
00160 float g = paramSet.FindOneFloat("gain", 1.f);
00161
00162 const SphericalFunction *sf = CreateSphericalFunction(paramSet, tp);
00163 SampleableSphericalFunction *ssf = NULL;
00164 if(sf)
00165 ssf = new SampleableSphericalFunction(boost::shared_ptr<const SphericalFunction>(sf));
00166
00167 Point P = paramSet.FindOnePoint("from", Point(0,0,0));
00168 Transform l2w = Translate(Vector(P.x, P.y, P.z)) * light2world;
00169 return new PointLight(l2w, L, g, ssf);
00170 }
00171
00172 static DynamicLoader::RegisterLight<PointLight> r("point");
00173 static DynamicLoader::RegisterLight<PointLight> rb("goniometric");
00174