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