// InfiniteAreaLight Method Definitions InfiniteAreaLight::InfiniteAreaLight(const Transform &LightToWorld, const Spectrum &L, int nSamples, const std::string &texmap) : Light((int)LightFlags::Infinite, LightToWorld, MediumInterface(), nSamples) { // Read texel data from _texmap_ and initialize _Lmap_ Point2i resolution; std::unique_ptr<RGBSpectrum[]> texels(nullptr); if (texmap != "") { texels = ReadImage(texmap, &resolution); if (texels) for (int i = 0; i < resolution.x * resolution.y; ++i) texels[i] *= L.ToRGBSpectrum(); } if (!texels) { resolution.x = resolution.y = 1; texels = std::unique_ptr<RGBSpectrum[]>(new RGBSpectrum[1]); texels[0] = L.ToRGBSpectrum(); } Lmap.reset(new MIPMap<RGBSpectrum>(resolution, texels.get())); // Initialize sampling PDFs for infinite area light // Compute scalar-valued image _img_ from environment map int width = 2 * Lmap->Width(), height = 2 * Lmap->Height(); std::unique_ptr<Float[]> img(new Float[width * height]); float fwidth = 0.5f / std::min(width, height); ParallelFor( [&](int64_t v) { Float vp = (v + .5f) / (Float)height; Float sinTheta = std::sin(Pi * (v + .5f) / height); for (int u = 0; u < width; ++u) { Float up = (u + .5f) / (Float)width; img[u + v * width] = Lmap->Lookup(Point2f(up, vp), fwidth).y(); img[u + v * width] *= sinTheta; } }, height, 32); // Compute sampling distributions for rows and columns of image distribution.reset(new Distribution2D(img.get(), width, height)); }
// InfiniteAreaLight Method Definitions InfiniteAreaLight::InfiniteAreaLight(const Transform &LightToWorld, const Spectrum &L, int nSamples, const std::string &texmap) : Light(LightFlags::Infinite, LightToWorld, nullptr, nSamples) { // Read texel data from _texmap_ and initialize _Lmap_ Point2i resolution; std::unique_ptr<RGBSpectrum[]> texels(nullptr); if (texmap != "") { texels = ReadImage(texmap, &resolution); if (texels) for (int i = 0; i < resolution.x * resolution.y; ++i) texels[i] *= L.ToRGBSpectrum(); } if (!texels) { resolution.x = resolution.y = 1; texels = std::unique_ptr<RGBSpectrum[]>(new RGBSpectrum[1]); texels[0] = L.ToRGBSpectrum(); } Lmap.reset(new MIPMap<RGBSpectrum>(resolution, texels.get())); // Initialize sampling PDFs for infinite area light // Compute scalar-valued image _img_ from environment map int width = resolution.x, height = resolution.y; Float filter = (Float)1. / std::max(width, height); std::unique_ptr<Float[]> img(new Float[width * height]); for (int v = 0; v < height; ++v) { Float vp = (Float)v / (Float)height; Float sinTheta = std::sin(Pi * Float(v + .5f) / Float(height)); for (int u = 0; u < width; ++u) { Float up = (Float)u / (Float)width; img[u + v * width] = Lmap->Lookup(Point2f(up, vp), filter).y(); img[u + v * width] *= sinTheta; } } // Compute sampling distributions for rows and columns of image distribution.reset(new Distribution2D(img.get(), width, height)); }
MedianCutEnvironmentLight::MedianCutEnvironmentLight(const Transform &light2world, const Spectrum &L, int ns_, const string &texmap) : Light(light2world, ns_), impl(new MedCutEnvImpl {nullptr, nullptr, ns_}) { int width = 0, height = 0; RGBSpectrum *texels = NULL; // Read texel data from _texmap_ into _texels_ if (texmap != "") { texels = ReadImage(texmap, &width, &height); if (texels) for (int i = 0; i < width * height; ++i) texels[i] *= L.ToRGBSpectrum(); } if (!texels) { width = height = 1; texels = new RGBSpectrum[1]; texels[0] = L.ToRGBSpectrum(); } impl->radianceMap = new MIPMap<RGBSpectrum>(width, height, texels); impl->width = width; impl->inv_w = 1.0f/(width-1); impl->height = height; impl->inv_h = 1.0f/(height-1); impl->createDistantLight = [this](const RGBSpectrum& s, float cy, float cx) { ParamSet p; float rgb[3]; s.ToRGB(rgb); p.AddRGBSpectrum("L", rgb, 3); const float theta = impl->inv_h*cy * M_PI , phi = impl->inv_w*cx * 2.f * M_PI; const float costheta = cosf(theta), sintheta = sinf(theta); const float sinphi = sinf(phi), cosphi = cosf(phi); const Point wi(-sintheta*cosphi, -sintheta*sinphi, -costheta); p.AddPoint(string("to"), &wi, 1); #if DEBUG >= 1 fprintf(stderr, "rgb (%f,%f,%f)\n", rgb[0], rgb[1], rgb[2]); #endif return CreateDistantLight(this->LightToWorld, p); }; impl->solid_angle = ((2.f * M_PI) / (width - 1)) * (M_PI / (1.f * (height - 1))); #if DEBUG >= 1 fprintf(stderr, "solid_angle = %f\n", impl->solid_angle); #endif for (int y = 0; y < height; ++y) { float sinTheta = sinf(M_PI * float(y + 0.5f)/height); for (int x = 0; x < width; ++x) texels[y*width + x] *= impl->solid_angle * sinTheta; } // Initialize energy sum array; the array is shifted for (1,1) // i.e. (0,*) and (*,0) are inserted 0-boundaries fprintf(stderr, "[+] [%10.2f] Initializing sum array\n", clock()*1.0/CLOCKS_PER_SEC); #if DEBUG >= 3 for (int y = 0; y < 5; ++y) { for (int x = 0; x < 5; ++x) { fprintf(stderr, "%.2f ", texels[y*width+x].y()); } fprintf(stderr, "\n"); } fprintf(stderr, "\n"); #endif vector<vector<float>> acc(height+1, vector<float>(width+1)); for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) acc[y+1][x+1] = acc[y+1][x] + texels[y*width + x].y(); #if DEBUG >= 3 for (int y = 0; y < 5; ++y) { for (int x = 0; x < 5; ++x) { fprintf(stderr, "%.2f ", acc[y][x]); } fprintf(stderr, "\n"); } fprintf(stderr, "\n"); #endif for (int x = 1; x <= width; ++x) for (int y = 1; y <= height; ++y) acc[y][x] += acc[y-1][x]; #if DEBUG >= 3 for (int y = 0; y < 5; ++y) { for (int x = 0; x < 5; ++x) { fprintf(stderr, "%.2f ", acc[y][x]); } fprintf(stderr, "\n"); } fprintf(stderr, "\n"); #endif // initialize median cut printf("[+] [%10.2f] Calculating median cut\n", clock()*1.0/CLOCKS_PER_SEC); subdivide(this->impl, 1, texels, acc, 0, 0, width-1, height-1); printf("[+] [%10.2f] Done with %d lights\n", clock()*1.0/CLOCKS_PER_SEC, static_cast<int>(impl->ls.size())); delete[] texels; // Initialize sampling PDFs for environment area light // Compute scalar-valued image _img_ from environment map float filter = 1.f / max(width, height); float *img = new float[width*height]; for (int v = 0; v < height; ++v) { float vp = (float)v / (float)height; float sinTheta = sinf(M_PI * float(v+.5f)/float(height)); for (int u = 0; u < width; ++u) { float up = (float)u / (float)width; img[u+v*width] = impl->radianceMap->Lookup(up, vp, filter).y(); img[u+v*width] *= sinTheta; } } // Compute sampling impl->distributions for rows and columns of image impl->distribution = new Distribution2D(img, width, height); delete[] img; }