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 "texture.h"
00028 #include "shape.h"
00029 #include "scene.h"
00030 #include "mipmap.h"
00031
00032 class InfiniteAreaLight : public Light {
00033 public:
00034
00035 InfiniteAreaLight(const Transform &light2world, const Spectrum &power, int ns, const string &texmap);
00036 ~InfiniteAreaLight();
00037 Spectrum Power(const Scene *scene) const {
00038 Point worldCenter;
00039 float worldRadius;
00040 scene->WorldBound().BoundingSphere(&worldCenter,
00041 &worldRadius);
00042 return Lbase * (radianceMap ? radianceMap->Lookup(.5f, .5f, .5f) : Spectrum(1.f)) *
00043 M_PI * worldRadius * worldRadius;
00044 }
00045 bool IsDeltaLight() const { return false; }
00046 Spectrum Le(const RayDifferential &r) const;
00047 Spectrum Sample_L(const Point &p, const Normal &n,
00048 float u1, float u2, Vector *wi, float *pdf,
00049 VisibilityTester *visibility) const;
00050 Spectrum Sample_L(const Point &p, float u1, float u2, Vector *wi, float *pdf,
00051 VisibilityTester *visibility) const;
00052 Spectrum Sample_L(const Scene *scene, float u1, float u2,
00053 float u3, float u4, Ray *ray, float *pdf) const;
00054 float Pdf(const Point &, const Normal &, const Vector &) const;
00055 float Pdf(const Point &, const Vector &) const;
00056 Spectrum Sample_L(const Point &P, Vector *w, VisibilityTester *visibility) const;
00057 private:
00058
00059 Spectrum Lbase;
00060 MIPMap<Spectrum> *radianceMap;
00061 };
00062
00063 InfiniteAreaLight::~InfiniteAreaLight() {
00064 delete radianceMap;
00065 }
00066 InfiniteAreaLight
00067 ::InfiniteAreaLight(const Transform &light2world,
00068 const Spectrum &L, int ns,
00069 const string &texmap)
00070 : Light(light2world, ns) {
00071 radianceMap = NULL;
00072 if (texmap != "") {
00073 int width, height;
00074 Spectrum *texels =
00075 ReadImage(texmap, &width, &height);
00076 if (texels)
00077 radianceMap =
00078 new MIPMap<Spectrum>(width, height, texels);
00079 delete[] texels;
00080 }
00081 Lbase = L;
00082 }
00083 Spectrum
00084 InfiniteAreaLight::Le(const RayDifferential &r) const {
00085 Vector w = r.d;
00086
00087 Spectrum L = Lbase;
00088 if (radianceMap != NULL) {
00089 Vector wh = Normalize(WorldToLight(w));
00090 float s = SphericalPhi(wh) * INV_TWOPI;
00091 float t = SphericalTheta(wh) * INV_PI;
00092 L *= radianceMap->Lookup(s, t);
00093 }
00094 return L;
00095 }
00096 Spectrum InfiniteAreaLight::Sample_L(const Point &p,
00097 const Normal &n, float u1, float u2,
00098 Vector *wi, float *pdf,
00099 VisibilityTester *visibility) const {
00100
00101 float x, y, z;
00102 ConcentricSampleDisk(u1, u2, &x, &y);
00103 z = sqrtf(max(0.f, 1.f - x*x - y*y));
00104 if (RandomFloat() < .5) z *= -1;
00105 *wi = Vector(x, y, z);
00106
00107 *pdf = fabsf(wi->z) * INV_TWOPI;
00108
00109 Vector v1, v2;
00110 CoordinateSystem(Normalize(Vector(n)), &v1, &v2);
00111 *wi = Vector(v1.x * wi->x + v2.x * wi->y + n.x * wi->z,
00112 v1.y * wi->x + v2.y * wi->y + n.y * wi->z,
00113 v1.z * wi->x + v2.z * wi->y + n.z * wi->z);
00114 visibility->SetRay(p, *wi);
00115 return Le(RayDifferential(p, *wi));
00116 }
00117 float InfiniteAreaLight::Pdf(const Point &, const Normal &n,
00118 const Vector &wi) const {
00119 return AbsDot(n, wi) * INV_TWOPI;
00120 }
00121 Spectrum InfiniteAreaLight::Sample_L(const Point &p,
00122 float u1, float u2, Vector *wi, float *pdf,
00123 VisibilityTester *visibility) const {
00124 *wi = UniformSampleSphere(u1, u2);
00125 *pdf = UniformSpherePdf();
00126 visibility->SetRay(p, *wi);
00127 return Le(RayDifferential(p, *wi));
00128 }
00129 float InfiniteAreaLight::Pdf(const Point &, const Vector &) const {
00130 return 1.f / (4.f * M_PI);
00131 }
00132 Spectrum InfiniteAreaLight::Sample_L(const Scene *scene,
00133 float u1, float u2, float u3, float u4,
00134 Ray *ray, float *pdf) const {
00135
00136 Point worldCenter;
00137 float worldRadius;
00138 scene->WorldBound().BoundingSphere(&worldCenter,
00139 &worldRadius);
00140 worldRadius *= 1.01f;
00141 Point p1 = worldCenter + worldRadius *
00142 UniformSampleSphere(u1, u2);
00143 Point p2 = worldCenter + worldRadius *
00144 UniformSampleSphere(u3, u4);
00145
00146 ray->o = p1;
00147 ray->d = Normalize(p2-p1);
00148
00149 Vector to_center = Normalize(worldCenter - p1);
00150 float costheta = AbsDot(to_center,ray->d);
00151 *pdf =
00152 costheta / ((4.f * M_PI * worldRadius * worldRadius));
00153 return Le(RayDifferential(ray->o, -ray->d));
00154 }
00155 Spectrum InfiniteAreaLight::Sample_L(const Point &p,
00156 Vector *wi, VisibilityTester *visibility) const {
00157 float pdf;
00158 Spectrum L = Sample_L(p, RandomFloat(), RandomFloat(),
00159 wi, &pdf, visibility);
00160 if (pdf == 0.f) return Spectrum(0.f);
00161 return L / pdf;
00162 }
00163 extern "C" DLLEXPORT Light *CreateLight(const Transform &light2world,
00164 const ParamSet ¶mSet) {
00165 Spectrum L = paramSet.FindOneSpectrum("L", Spectrum(1.0));
00166 string texmap = paramSet.FindOneString("mapname", "");
00167 int nSamples = paramSet.FindOneInt("nsamples", 1);
00168 return new InfiniteAreaLight(light2world, L, nSamples, texmap);
00169 }