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 #include "mipmap.h"
00029
00030 class ProjectionLight : public Light {
00031 public:
00032
00033 ProjectionLight(const Transform &light2world, const Spectrum &intensity,
00034 const string &texname, float fov);
00035 ~ProjectionLight();
00036 Spectrum Sample_L(const Point &p, Vector *wi, VisibilityTester *vis) const;
00037 bool IsDeltaLight() const { return true; }
00038 Spectrum Projection(const Vector &w) const;
00039 Spectrum Power(const Scene *) const {
00040 return Intensity * 2.f * M_PI * (1.f - cosTotalWidth) *
00041 projectionMap->Lookup(.5f, .5f, .5f);
00042 }
00043 Spectrum Sample_L(const Point &P, float u1, float u2, Vector *wo,
00044 float *pdf, VisibilityTester *visibility) const;
00045 Spectrum Sample_L(const Scene *scene, float u1, float u2,
00046 float u3, float u4, Ray *ray, float *pdf) const;
00047 float Pdf(const Point &, const Vector &) const;
00048 private:
00049
00050 MIPMap<Spectrum> *projectionMap;
00051 Point lightPos;
00052 Spectrum Intensity;
00053 Transform lightProjection;
00054 float hither, yon;
00055 float screenX0, screenX1, screenY0, screenY1;
00056 float cosTotalWidth;
00057 };
00058
00059 ProjectionLight::
00060 ProjectionLight(const Transform &light2world,
00061 const Spectrum &intensity, const string &texname,
00062 float fov)
00063 : Light(light2world) {
00064 lightPos = LightToWorld(Point(0,0,0));
00065 Intensity = intensity;
00066
00067 int width, height;
00068 Spectrum *texels = ReadImage(texname, &width, &height);
00069 if (texels)
00070 projectionMap =
00071 new MIPMap<Spectrum>(width, height, texels);
00072 else
00073 projectionMap = NULL;
00074 delete[] texels;
00075
00076 float aspect = float(width) / float(height);
00077 if (aspect > 1.f) {
00078 screenX0 = -aspect; screenX1 = aspect;
00079 screenY0 = -1.f; screenY1 = 1.f;
00080 }
00081 else {
00082 screenX0 = -1.f; screenX1 = 1.f;
00083 screenY0 = -1.f / aspect; screenY1 = 1.f / aspect;
00084 }
00085 hither = RAY_EPSILON;
00086 yon = 1e30f;
00087 lightProjection = Perspective(fov, hither, yon);
00088
00089 float opposite = tanf(Radians(fov) / 2.f);
00090 float tanDiag = opposite * sqrtf(1.f + 1.f/(aspect*aspect));
00091 cosTotalWidth = cosf(atanf(tanDiag));
00092 }
00093 ProjectionLight::~ProjectionLight() { delete projectionMap; }
00094 Spectrum ProjectionLight::Sample_L(const Point &p, Vector *wi,
00095 VisibilityTester *visibility) const {
00096 *wi = Normalize(lightPos - p);
00097 visibility->SetSegment(p, lightPos);
00098 return Intensity * Projection(-*wi) /
00099 DistanceSquared(lightPos, p);
00100 }
00101 Spectrum ProjectionLight::Projection(const Vector &w) const {
00102 Vector wl = WorldToLight(w);
00103
00104 if (wl.z < hither) return 0.;
00105
00106 Point Pl = lightProjection(Point(wl.x, wl.y, wl.z));
00107 if (Pl.x < screenX0 || Pl.x > screenX1 ||
00108 Pl.y < screenY0 || Pl.y > screenY1) return 0.;
00109 if (!projectionMap) return 1;
00110 float s = (Pl.x - screenX0) / (screenX1 - screenX0);
00111 float t = (Pl.y - screenY0) / (screenY1 - screenY0);
00112 return projectionMap->Lookup(s, t);
00113 }
00114 Spectrum ProjectionLight::Sample_L(const Point &p, float u1, float u2,
00115 Vector *wi, float *pdf,
00116 VisibilityTester *visibility) const {
00117 *wi = Normalize(lightPos - p);
00118 *pdf = 1.f;
00119 visibility->SetSegment(p, lightPos);
00120 return Intensity * Projection(-*wi) / DistanceSquared(lightPos, p);
00121 }
00122 Spectrum ProjectionLight::Sample_L(const Scene *scene, float u1, float u2,
00123 float u3, float u4, Ray *ray, float *pdf) const {
00124 ray->o = lightPos;
00125 Vector v = UniformSampleCone(u1, u2, cosTotalWidth);
00126 ray->d = LightToWorld(v);
00127 *pdf = UniformConePdf(cosTotalWidth);
00128 return Intensity * Projection(ray->d);
00129 }
00130 float ProjectionLight::Pdf(const Point &, const Vector &) const {
00131 return 0.;
00132 }
00133 extern "C" DLLEXPORT Light *CreateLight(const Transform &light2world,
00134 const ParamSet ¶mSet) {
00135 Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0));
00136 float fov = paramSet.FindOneFloat("fov", 45.);
00137 string texname = paramSet.FindOneString("mapname", "");
00138 return new ProjectionLight(light2world, I, texname, fov);
00139 }