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