void ParamSet::AddSampledSpectrumFiles(const string &name, const char **names, int nItems) { EraseSpectrum(name); Spectrum *s = new Spectrum[nItems]; for (int i = 0; i < nItems; ++i) { string fn = AbsolutePath(ResolveFilename(names[i])); if (cachedSpectra.find(fn) != cachedSpectra.end()) { s[i] = cachedSpectra[fn]; continue; } vector<float> vals; if (!ReadFloatFile(fn.c_str(), &vals)) { Warning("Unable to read SPD file \"%s\". Using black distribution.", fn.c_str()); s[i] = Spectrum(0.); } else { if (vals.size() % 2) { Warning("Extra value found in spectrum file \"%s\". " "Ignoring it.", fn.c_str()); } vector<float> wls, v; for (uint32_t j = 0; j < vals.size() / 2; ++j) { wls.push_back(vals[2*j]); v.push_back(vals[2*j+1]); } s[i] = Spectrum::FromSampled(&wls[0], &v[0], wls.size()); } cachedSpectra[fn] = s[i]; } spectra.push_back(new ParamSetItem<Spectrum>(name, s, nItems)); delete[] s; }
// RealisticCamera Method Definitions RealisticCamera::RealisticCamera(const AnimatedTransform &CameraToWorld, Float shutterOpen, Float shutterClose, Float apertureDiameter, Float focusDistance, bool simpleWeighting, const char *lensFile, Film *film, const Medium *medium) : Camera(CameraToWorld, shutterOpen, shutterClose, film, medium), simpleWeighting(simpleWeighting) { // Load element data from lens description file std::vector<Float> lensData; if (ReadFloatFile(lensFile, &lensData) == false) { Error("Error reading lens specification file \"%s\".", lensFile); return; } if ((lensData.size() % 4) != 0) { Error( "Excess values in lens specification file \"%s\"; " "must be multiple-of-four values, read %d.", lensFile, (int)lensData.size()); return; } for (int i = 0; i < (int)lensData.size(); i += 4) { if (lensData[i] == 0) { if (apertureDiameter > lensData[i + 3]) { Warning( "Specified aperture diameter %f is greater than maximum " "possible %f. Clamping it.", apertureDiameter, lensData[i + 3]); } else { lensData[i + 3] = apertureDiameter; } } elementInterfaces.push_back((LensElementInterface) { lensData[i] * (Float).001, lensData[i + 1] * (Float).001, lensData[i + 2], lensData[i + 3] * Float(.001) / Float(2.) }); } // Compute lens--film distance for given focus distance Float fb = FocusBinarySearch(focusDistance); Info("Binary search focus: %f -> %f\n", fb, FocusDistance(fb)); elementInterfaces.back().thickness = FocusThickLens(focusDistance); Info("Thick lens focus: %f -> %f\n", elementInterfaces.back().thickness, FocusDistance(elementInterfaces.back().thickness)); // Compute exit pupil bounds at sampled points on the film int nSamples = 64; exitPupilBounds.resize(nSamples); ParallelFor([&](int i) { Float r0 = (Float)i / nSamples * film->diagonal / 2; Float r1 = (Float)(i + 1) / nSamples * film->diagonal / 2; exitPupilBounds[i] = BoundExitPupil(r0, r1); }, nSamples); }
void ParamSet::AddSampledSpectrumFiles(const std::string &name, const char **names, int nValues) { EraseSpectrum(name); std::unique_ptr<Spectrum[]> s(new Spectrum[nValues]); for (int i = 0; i < nValues; ++i) { std::string fn = AbsolutePath(ResolveFilename(names[i])); if (cachedSpectra.find(fn) != cachedSpectra.end()) { s[i] = cachedSpectra[fn]; continue; } std::vector<Float> vals; if (!ReadFloatFile(fn.c_str(), &vals)) { Warning( "Unable to read SPD file \"%s\". Using black distribution.", fn.c_str()); s[i] = Spectrum(0.); } else { if (vals.size() % 2) { Warning( "Extra value found in spectrum file \"%s\". " "Ignoring it.", fn.c_str()); } std::vector<Float> wls, v; for (size_t j = 0; j < vals.size() / 2; ++j) { wls.push_back(vals[2 * j]); v.push_back(vals[2 * j + 1]); } s[i] = Spectrum::FromSampled(&wls[0], &v[0], wls.size()); } cachedSpectra[fn] = s[i]; } std::shared_ptr<ParamSetItem<Spectrum>> psi( new ParamSetItem<Spectrum>(name, std::move(s), nValues)); spectra.push_back(psi); }
void DipoleSubsurfaceIntegrator::Preprocess(const Scene *scene, const Camera *camera, const Renderer *renderer) { if (scene->lights.size() == 0) return; vector<SurfacePoint> pts; // Get _SurfacePoint_s for translucent objects in scene if (filename != "") { // Initialize _SurfacePoint_s from file vector<float> fpts; if (ReadFloatFile(filename.c_str(), &fpts)) { if ((fpts.size() % 8) != 0) Error("Excess values (%d) in points file \"%s\"", int(fpts.size() % 8), filename.c_str()); for (u_int i = 0; i < fpts.size(); i += 8) pts.push_back(SurfacePoint(Point(fpts[i], fpts[i+1], fpts[i+2]), Normal(fpts[i+3], fpts[i+4], fpts[i+5]), fpts[i+6], fpts[i+7])); } } if (pts.size() == 0) { Point pCamera = camera->CameraToWorld(camera->shutterOpen, Point(0, 0, 0)); FindPoissonPointDistribution(pCamera, camera->shutterOpen, minSampleDist, scene, &pts); } // Compute irradiance values at sample points RNG rng; MemoryArena arena; PBRT_SUBSURFACE_STARTED_COMPUTING_IRRADIANCE_VALUES(); ProgressReporter progress(pts.size(), "Computing Irradiances"); for (uint32_t i = 0; i < pts.size(); ++i) { SurfacePoint &sp = pts[i]; Spectrum E(0.f); for (uint32_t j = 0; j < scene->lights.size(); ++j) { // Add irradiance from light at point const Light *light = scene->lights[j]; Spectrum Elight = 0.f; int nSamples = RoundUpPow2(light->nSamples); uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; uint32_t compScramble = rng.RandomUInt(); for (int s = 0; s < nSamples; ++s) { float lpos[2]; Sample02(s, scramble, lpos); float lcomp = VanDerCorput(s, compScramble); LightSample ls(lpos[0], lpos[1], lcomp); Vector wi; float lightPdf; VisibilityTester visibility; Spectrum Li = light->Sample_L(sp.p, sp.rayEpsilon, ls, camera->shutterOpen, &wi, &lightPdf, &visibility); if (Dot(wi, sp.n) <= 0.) continue; if (Li.IsBlack() || lightPdf == 0.f) continue; Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena); if (visibility.Unoccluded(scene)) Elight += Li * AbsDot(wi, sp.n) / lightPdf; } E += Elight / nSamples; } if (E.y() > 0.f) { irradiancePoints.push_back(IrradiancePoint(sp, E)); PBRT_SUBSURFACE_COMPUTED_IRRADIANCE_AT_POINT(&sp, &E); } arena.FreeAll(); progress.Update(); } progress.Done(); PBRT_SUBSURFACE_FINISHED_COMPUTING_IRRADIANCE_VALUES(); // Create octree of clustered irradiance samples octree = octreeArena.Alloc<SubsurfaceOctreeNode>(); for (uint32_t i = 0; i < irradiancePoints.size(); ++i) octreeBounds = Union(octreeBounds, irradiancePoints[i].p); for (uint32_t i = 0; i < irradiancePoints.size(); ++i) octree->Insert(octreeBounds, &irradiancePoints[i], octreeArena); octree->InitHierarchy(); }
MeasuredMaterial::MeasuredMaterial(string matName, const string &filename, Reference<Texture<float> > bump): Material(matName) { bumpMap = bump; const char *suffix = strrchr(filename.c_str(), '.'); regularHalfangleData = NULL; thetaPhiData = NULL; if (!suffix) Error("No suffix in measured BRDF filename \"%s\". " "Can't determine file type (.brdf / .merl)", filename.c_str()); else if (!strcmp(suffix, ".brdf") || !strcmp(suffix, ".BRDF")) { // Load $(\theta, \phi)$ measured BRDF data if (loadedThetaPhi.find(filename) != loadedThetaPhi.end()) { thetaPhiData = loadedThetaPhi[filename]; return; } vector<float> values; if (!ReadFloatFile(filename.c_str(), &values)) { Error("Unable to read BRDF data from file \"%s\"", filename.c_str()); return; } uint32_t pos = 0; int numWls = int(values[pos++]); if ((values.size() - 1 - numWls) % (4 + numWls) != 0) { Error("Excess or insufficient data in theta, phi BRDF file \"%s\"", filename.c_str()); return; } vector<float> wls; for (int i = 0; i < numWls; ++i) wls.push_back(values[pos++]); BBox bbox; vector<IrregIsotropicBRDFSample> samples; while (pos < values.size()) { float thetai = values[pos++]; float phii = values[pos++]; float thetao = values[pos++]; float phio = values[pos++]; Vector wo = SphericalDirection(sinf(thetao), cosf(thetao), phio); Vector wi = SphericalDirection(sinf(thetai), cosf(thetai), phii); Spectrum s = Spectrum::FromSampled(&wls[0], &values[pos], numWls); pos += numWls; pbrt::Point p = BRDFRemap(wo, wi); samples.push_back(IrregIsotropicBRDFSample(p, s)); bbox = Union(bbox, p); } loadedThetaPhi[filename] = thetaPhiData = new KdTree<IrregIsotropicBRDFSample>(samples); } else { // Load RegularHalfangle BRDF Data nThetaH = 90; nThetaD = 90; nPhiD = 180; if (loadedRegularHalfangle.find(filename) != loadedRegularHalfangle.end()) { regularHalfangleData = loadedRegularHalfangle[filename]; return; } FILE *f = fopen(filename.c_str(), "rb"); if (!f) { Error("Unable to open BRDF data file \"%s\"", filename.c_str()); return; } int dims[3]; if (fread(dims, sizeof(int), 3, f) != 3) { Error("Premature end-of-file in measured BRDF data file \"%s\"", filename.c_str()); fclose(f); return; } uint32_t n = dims[0] * dims[1] * dims[2]; if (n != nThetaH * nThetaD * nPhiD) { Error("Dimensions don't match\n"); fclose(f); return; } regularHalfangleData = new float[3*n]; const uint32_t chunkSize = 2*nPhiD; double *tmp = ALLOCA(double, chunkSize); uint32_t nChunks = n / chunkSize; Assert((n % chunkSize) == 0); float scales[3] = { 1.f/1500.f, 1.15f/1500.f, 1.66f/1500.f }; for (int c = 0; c < 3; ++c) { int offset = 0; for (uint32_t i = 0; i < nChunks; ++i) { if (fread(tmp, sizeof(double), chunkSize, f) != chunkSize) { Error("Premature end-of-file in measured BRDF data file \"%s\"", filename.c_str()); delete[] regularHalfangleData; regularHalfangleData = NULL; fclose(f); return; } for (uint32_t j = 0; j < chunkSize; ++j) regularHalfangleData[3 * offset++ + c] = max(0., tmp[j] * scales[c]); } } loadedRegularHalfangle[filename] = regularHalfangleData; fclose(f); } }