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