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