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 "infinitesample.h"
00027 #include "imagereader.h"
00028 #include "paramset.h"
00029 using namespace lux;
00030
00031
00032 InfiniteAreaLightIS::~InfiniteAreaLightIS() {
00033 delete radianceMap;
00034 }
00035 InfiniteAreaLightIS
00036 ::InfiniteAreaLightIS(const Transform &light2world,
00037 const Spectrum &L, int ns,
00038 const string &texmap)
00039 : Light(light2world, ns)
00040 {
00041 int width = 0, height = 0;
00042 Lbase = L;
00043 radianceMap = NULL;
00044 if (texmap != "") {
00045 auto_ptr<ImageData> imgdata(ReadImage(texmap));
00046 if(imgdata.get() !=NULL)
00047 {
00048 width=imgdata->getWidth();
00049 height=imgdata->getHeight();
00050 radianceMap = imgdata->createMIPMap<Spectrum>();
00051 }
00052 }
00053 if (radianceMap == NULL)
00054 return;
00055
00056 float filter = 1.f / max(width, height);
00057 int nu = width, nv = height;
00058 float *img = new float[width*height];
00059 for (int x = 0; x < nu; ++x) {
00060 float xp = (float)x / (float)nu;
00061 for (int y = 0; y < nv; ++y) {
00062 float yp = (float)y / (float)nv;
00063 img[y+x*nv] = radianceMap->Lookup(xp, yp, filter).y();
00064 }
00065 }
00066
00067 float *func = (float *)alloca(max(nu, nv) * sizeof(float));
00068 float *sinVals = (float *)alloca(nv * sizeof(float));
00069 for (int i = 0; i < nv; ++i)
00070 sinVals[i] = sin(M_PI * float(i+.5)/float(nv));
00071 vDistribs = new Distribution1D *[nu];
00072 for (int u = 0; u < nu; ++u) {
00073
00074 for (int v = 0; v < nv; ++v)
00075 func[v] = img[u*nv+v] *= sinVals[v];
00076 vDistribs[u] = new Distribution1D(func, nv);
00077 }
00078
00079 for (int u = 0; u < nu; ++u)
00080 func[u] = vDistribs[u]->funcInt;
00081 uDistrib = new Distribution1D(func, nu);
00082 delete[] img;
00083 }
00084 SWCSpectrum
00085 InfiniteAreaLightIS::Le(const RayDifferential &r) const {
00086 Vector w = r.d;
00087
00088 Spectrum L = Lbase;
00089 if (radianceMap != NULL) {
00090 Vector wh = Normalize(WorldToLight(w));
00091 float s = SphericalPhi(wh) * INV_TWOPI;
00092 float t = SphericalTheta(wh) * INV_PI;
00093 L *= radianceMap->Lookup(s, t);
00094 }
00095 return L;
00096 }
00097 SWCSpectrum InfiniteAreaLightIS::Sample_L(const Point &p, float u1,
00098 float u2, float u3, Vector *wi, float *pdf,
00099 VisibilityTester *visibility) const {
00100
00101 float pdfs[2];
00102 float fu = uDistrib->Sample(u1, &pdfs[0]);
00103 int u = Clamp(Float2Int(fu), 0, uDistrib->count-1);
00104 float fv = vDistribs[u]->Sample(u2, &pdfs[1]);
00105
00106 float theta = fv * vDistribs[u]->invCount * M_PI;
00107 float phi = fu * uDistrib->invCount * 2.f * M_PI;
00108 float costheta = cos(theta), sintheta = sin(theta);
00109 float sinphi = sin(phi), cosphi = cos(phi);
00110 *wi = LightToWorld(Vector(sintheta * cosphi, sintheta * sinphi,
00111 costheta));
00112
00113 *pdf = (pdfs[0] * pdfs[1]) / (2. * M_PI * M_PI * sintheta);
00114
00115 visibility->SetRay(p, *wi);
00116 return Lbase * radianceMap->Lookup(fu * uDistrib->invCount,
00117 fv * vDistribs[u]->invCount);
00118 }
00119 float InfiniteAreaLightIS::Pdf(const Point &,
00120 const Vector &w) const {
00121 Vector wi = WorldToLight(w);
00122 float theta = SphericalTheta(wi), phi = SphericalPhi(wi);
00123 int u = Clamp(Float2Int(phi * INV_TWOPI * uDistrib->count),
00124 0, uDistrib->count-1);
00125 int v = Clamp(Float2Int(theta * INV_PI * vDistribs[u]->count),
00126 0, vDistribs[u]->count-1);
00127 return (uDistrib->func[u] * vDistribs[u]->func[v]) /
00128 (uDistrib->funcInt * vDistribs[u]->funcInt) *
00129 1.f / (2.f * M_PI * M_PI * sin(theta));
00130 }
00131 SWCSpectrum InfiniteAreaLightIS::Sample_L(const Scene *scene,
00132 float u1, float u2, float u3, float u4,
00133 Ray *ray, float *pdf) const {
00134
00135 Point worldCenter;
00136 float worldRadius;
00137 scene->WorldBound().BoundingSphere(&worldCenter,
00138 &worldRadius);
00139 worldRadius *= 1.01f;
00140 Point p1 = worldCenter + worldRadius *
00141 UniformSampleSphere(u1, u2);
00142 Point p2 = worldCenter + worldRadius *
00143 UniformSampleSphere(u3, u4);
00144
00145 ray->o = p1;
00146 ray->d = Normalize(p2-p1);
00147
00148 Vector to_center = Normalize(worldCenter - p1);
00149 float costheta = AbsDot(to_center,ray->d);
00150 *pdf =
00151 costheta / ((4.f * M_PI * worldRadius * worldRadius));
00152 return Le(RayDifferential(ray->o, -ray->d));
00153 }
00154 SWCSpectrum InfiniteAreaLightIS::Sample_L(const Point &p,
00155 Vector *wi, VisibilityTester *visibility) const {
00156 float pdf;
00157 SWCSpectrum L = Sample_L(p, lux::random::floatValue(), lux::random::floatValue(),
00158 lux::random::floatValue(), wi, &pdf, visibility);
00159 if (pdf == 0.) return SWCSpectrum(0.);
00160 return L / pdf;
00161 }
00162
00163 Light* InfiniteAreaLightIS::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
00169 return new InfiniteAreaLightIS(light2world, L, nSamples, texmap);
00170 }