00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 #include "stdafx.h"
00027 #include "lights/spot.h"
00028 #include "paramset.h"
00029 #include "montecarlo.h"
00030 
00031 
00032 SpotLight::SpotLight(const Transform &light2world,
00033                      const Spectrum &intensity, float width, float fall)
00034     : Light(light2world) {
00035     lightPos = LightToWorld(Point(0,0,0));
00036     Intensity = intensity;
00037     cosTotalWidth = cosf(Radians(width));
00038     cosFalloffStart = cosf(Radians(fall));
00039 }
00040 
00041 
00042 Spectrum SpotLight::Sample_L(const Point &p, float pEpsilon,
00043         const LightSample &ls, float time, Vector *wi,
00044         float *pdf, VisibilityTester *visibility) const {
00045     *wi = Normalize(lightPos - p);
00046     *pdf = 1.f;
00047     visibility->SetSegment(p, pEpsilon, lightPos, 0., time);
00048     return Intensity * Falloff(-*wi) / DistanceSquared(lightPos, p);
00049 }
00050 
00051 
00052 float SpotLight::Falloff(const Vector &w) const {
00053     Vector wl = Normalize(WorldToLight(w));
00054     float costheta = wl.z;
00055     if (costheta < cosTotalWidth)     return 0.;
00056     if (costheta > cosFalloffStart)   return 1.;
00057     
00058     float delta = (costheta - cosTotalWidth) /
00059                   (cosFalloffStart - cosTotalWidth);
00060     return delta*delta*delta*delta;
00061 }
00062 
00063 
00064 Spectrum SpotLight::Power(const Scene *) const {
00065     return Intensity * 2.f * M_PI *
00066            (1.f - .5f * (cosFalloffStart + cosTotalWidth));
00067 }
00068 
00069 
00070 SpotLight *CreateSpotLight(const Transform &l2w, const ParamSet ¶mSet) {
00071     Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0));
00072     Spectrum sc = paramSet.FindOneSpectrum("scale", Spectrum(1.0));
00073     float coneangle = paramSet.FindOneFloat("coneangle", 30.);
00074     float conedelta = paramSet.FindOneFloat("conedeltaangle", 5.);
00075     
00076     Point from = paramSet.FindOnePoint("from", Point(0,0,0));
00077     Point to = paramSet.FindOnePoint("to", Point(0,0,1));
00078     Vector dir = Normalize(to - from);
00079     Vector du, dv;
00080     CoordinateSystem(dir, &du, &dv);
00081     Transform dirToZ =
00082         Transform(Matrix4x4( du.x,  du.y,  du.z, 0.,
00083                              dv.x,  dv.y,  dv.z, 0.,
00084                             dir.x, dir.y, dir.z, 0.,
00085                                 0,     0,     0, 1.));
00086     Transform light2world = l2w *
00087         Translate(Vector(from.x, from.y, from.z)) * Inverse(dirToZ);
00088     return new SpotLight(light2world, I * sc, coneangle,
00089         coneangle-conedelta);
00090 }
00091 
00092 
00093 float SpotLight::Pdf(const Point &, const Vector &) const {
00094     return 0.;
00095 }
00096 
00097 
00098 Spectrum SpotLight::Sample_L(const Scene *scene, const LightSample &ls,
00099         float u1, float u2, float time, Ray *ray, Normal *Ns,
00100         float *pdf) const {
00101     Vector v = UniformSampleCone(ls.uPos[0], ls.uPos[1], cosTotalWidth);
00102     *ray = Ray(lightPos, LightToWorld(v), 0.f, INFINITY, time);
00103     *Ns = (Normal)ray->d;
00104     *pdf = UniformConePdf(cosTotalWidth);
00105     return Intensity * Falloff(ray->d);
00106 }
00107 
00108