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 "projection.h"
00027 #include "imagereader.h"
00028 #include "mc.h"
00029 #include "paramset.h"
00030
00031 using namespace lux;
00032
00033
00034 ProjectionLight::
00035 ProjectionLight(const Transform &light2world,
00036 const Spectrum &intensity, const string &texname,
00037 float fov)
00038 : Light(light2world) {
00039 lightPos = LightToWorld(Point(0,0,0));
00040 Intensity = intensity;
00041
00042 int width = 0, height = 0;
00043 auto_ptr<ImageData> imgdata(ReadImage(texname));
00044 if (imgdata.get()!=NULL) {
00045 width=imgdata->getWidth();
00046 height=imgdata->getHeight();
00047 projectionMap =imgdata->createMIPMap<Spectrum>();
00048 }
00049 else
00050 projectionMap = NULL;
00051
00052
00053 float aspect = float(width) / float(height);
00054 if (aspect > 1.f) {
00055 screenX0 = -aspect; screenX1 = aspect;
00056 screenY0 = -1.f; screenY1 = 1.f;
00057 }
00058 else {
00059 screenX0 = -1.f; screenX1 = 1.f;
00060 screenY0 = -1.f / aspect; screenY1 = 1.f / aspect;
00061 }
00062 hither = RAY_EPSILON;
00063 yon = 1e30f;
00064 lightProjection = Perspective(fov, hither, yon);
00065
00066 float opposite = tanf(Radians(fov) / 2.f);
00067 float tanDiag = opposite * sqrtf(1.f + 1.f/(aspect*aspect));
00068 cosTotalWidth = cosf(atanf(tanDiag));
00069 }
00070 ProjectionLight::~ProjectionLight() { delete projectionMap; }
00071 SWCSpectrum ProjectionLight::Sample_L(const Point &p, Vector *wi,
00072 VisibilityTester *visibility) const {
00073 *wi = Normalize(lightPos - p);
00074 visibility->SetSegment(p, lightPos);
00075 return Intensity * Projection(-*wi) /
00076 DistanceSquared(lightPos, p);
00077 }
00078 Spectrum ProjectionLight::Projection(const Vector &w) const {
00079 Vector wl = WorldToLight(w);
00080
00081 if (wl.z < hither) return 0.;
00082
00083 Point Pl = lightProjection(Point(wl.x, wl.y, wl.z));
00084 if (Pl.x < screenX0 || Pl.x > screenX1 ||
00085 Pl.y < screenY0 || Pl.y > screenY1) return 0.;
00086 if (!projectionMap) return 1;
00087 float s = (Pl.x - screenX0) / (screenX1 - screenX0);
00088 float t = (Pl.y - screenY0) / (screenY1 - screenY0);
00089 return projectionMap->Lookup(s, t);
00090 }
00091 SWCSpectrum ProjectionLight::Sample_L(const Point &p, float u1, float u2,
00092 float u3, Vector *wi, float *pdf,
00093 VisibilityTester *visibility) const {
00094 *wi = Normalize(lightPos - p);
00095 *pdf = 1.f;
00096 visibility->SetSegment(p, lightPos);
00097 return Intensity * Projection(-*wi) / DistanceSquared(lightPos, p);
00098 }
00099 SWCSpectrum ProjectionLight::Sample_L(const Scene *scene, float u1, float u2,
00100 float u3, float u4, Ray *ray, float *pdf) const {
00101 ray->o = lightPos;
00102 Vector v = UniformSampleCone(u1, u2, cosTotalWidth);
00103 ray->d = LightToWorld(v);
00104 *pdf = UniformConePdf(cosTotalWidth);
00105 return Intensity * Projection(ray->d);
00106 }
00107 float ProjectionLight::Pdf(const Point &, const Vector &) const {
00108 return 0.;
00109 }
00110 Light* ProjectionLight::CreateLight(const Transform &light2world,
00111 const ParamSet ¶mSet) {
00112 Spectrum I = paramSet.FindOneSpectrum("I", Spectrum(1.0));
00113 float fov = paramSet.FindOneFloat("fov", 45.);
00114 string texname = paramSet.FindOneString("mapname", "");
00115 return new ProjectionLight(light2world, I, texname, fov);
00116 }