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 #include "pbrt.h"
00026 #include "light.h"
00027 #include "shape.h"
00028
00029 class SpotLight : public Light {
00030 public:
00031
00032 SpotLight(const Transform &light2world, const Spectrum &, float width, float fall);
00033 Spectrum Sample_L(const Point &p, Vector *wi, VisibilityTester *vis) const;
00034 bool IsDeltaLight() const { return true; }
00035 float Falloff(const Vector &w) const;
00036 Spectrum Power(const Scene *) const {
00037 return Intensity * 2.f * M_PI *
00038 (1.f - .5f * (cosFalloffStart + cosTotalWidth));
00039 }
00040 Spectrum Sample_L(const Point &P, float u1, float u2,
00041 Vector *wo, float *pdf, VisibilityTester *visibility) const;
00042 Spectrum Sample_L(const Scene *scene, float u1, float u2,
00043 float u3, float u4, Ray *ray, float *pdf) const;
00044 float Pdf(const Point &, const Vector &) const;
00045 private:
00046
00047 float cosTotalWidth, cosFalloffStart;
00048 Point lightPos;
00049 Spectrum Intensity;
00050 };
00051
00052 SpotLight::SpotLight(const Transform &light2world,
00053 const Spectrum &intensity, float width, float fall)
00054 : Light(light2world) {
00055 lightPos = LightToWorld(Point(0,0,0));
00056 Intensity = intensity;
00057 cosTotalWidth = cosf(Radians(width));
00058 cosFalloffStart = cosf(Radians(fall));
00059 }
00060 Spectrum SpotLight::Sample_L(const Point &p, Vector *wi,
00061 VisibilityTester *visibility) const {
00062 *wi = Normalize(lightPos - p);
00063 visibility->SetSegment(p, lightPos);
00064 return Intensity * Falloff(-*wi) /
00065 DistanceSquared(lightPos, p);
00066 }
00067 float SpotLight::Falloff(const Vector &w) const {
00068 Vector wl = Normalize(WorldToLight(w));
00069 float costheta = wl.z;
00070 if (costheta < cosTotalWidth)
00071 return 0.;
00072 if (costheta > cosFalloffStart)
00073 return 1.;
00074
00075 float delta = (costheta - cosTotalWidth) /
00076 (cosFalloffStart - cosTotalWidth);
00077 return delta*delta*delta*delta;
00078 }
00079 Spectrum SpotLight::Sample_L(const Point &p, float u1, float u2,
00080 Vector *wi, float *pdf, VisibilityTester *visibility) const {
00081 *pdf = 1.f;
00082 return Sample_L(p, wi, visibility);
00083 }
00084 float SpotLight::Pdf(const Point &, const Vector &) const {
00085 return 0.;
00086 }
00087 Spectrum SpotLight::Sample_L(const Scene *scene, float u1,
00088 float u2, float u3, float u4,
00089 Ray *ray, float *pdf) const {
00090 ray->o = lightPos;
00091 Vector v = UniformSampleCone(u1, u2, cosTotalWidth);
00092 ray->d = LightToWorld(v);
00093 *pdf = UniformConePdf(cosTotalWidth);
00094 return Intensity * Falloff(ray->d);
00095 }
00096 extern "C" DLLEXPORT Light *CreateLight(const Transform &l2w, const ParamSet ¶mSet) {
00097 Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0));
00098 float coneangle = paramSet.FindOneFloat("coneangle", 30.);
00099 float conedelta = paramSet.FindOneFloat("conedeltaangle", 5.);
00100
00101 Point from = paramSet.FindOnePoint("from", Point(0,0,0));
00102 Point to = paramSet.FindOnePoint("to", Point(0,0,1));
00103 Vector dir = Normalize(to - from);
00104 Vector du, dv;
00105 CoordinateSystem(dir, &du, &dv);
00106 Transform dirToZ =
00107 Transform(new Matrix4x4( du.x, du.y, du.z, 0.,
00108 dv.x, dv.y, dv.z, 0.,
00109 dir.x, dir.y, dir.z, 0.,
00110 0, 0, 0, 1.));
00111 Transform light2world =
00112 l2w *
00113 Translate(Vector(from.x, from.y, from.z)) *
00114 dirToZ.GetInverse();
00115 return new SpotLight(light2world, I, coneangle,
00116 coneangle-conedelta);
00117 }