void BestCandidate2D(float table[][2], int totalSamples, RNG &rng, SampleGrid *grid) { SampleGrid localGrid; if (!grid) grid = &localGrid; ProgressReporter progress(totalSamples-1, "Throwing Darts"); // Generate first 2D sample arbitrarily table[0][0] = rng.RandomFloat(); table[0][1] = rng.RandomFloat(); addSampleToGrid(table, 0, grid); for (int currentSample = 1; currentSample < totalSamples; ++currentSample) { // Generate next best 2D image sample float maxDist2 = 0.; int numCandidates = 500 * currentSample; for (int currentCandidate = 0; currentCandidate < numCandidates; ++currentCandidate) { // Generate a random candidate sample float candidate[2]; candidate[0] = rng.RandomFloat(); candidate[1] = rng.RandomFloat(); // Loop over neighboring grid cells and check distances float sampleDist2 = INFINITY; int gu = GRID(candidate[0]), gv = GRID(candidate[1]); for (int du = -1; du <= 1; ++du) { for (int dv = -1; dv <= 1; ++dv) { // Compute (u,v) grid cell to check int u = gu + du, v = gv + dv; if (u < 0) u += BC_GRID_SIZE; if (u >= BC_GRID_SIZE) u -= BC_GRID_SIZE; if (v < 0) v += BC_GRID_SIZE; if (v >= BC_GRID_SIZE) v -= BC_GRID_SIZE; // Update minimum squared distance from cell's samples for (uint32_t g = 0; g < (*grid)[u][v].size(); ++g) { int s = (*grid)[u][v][g]; float xdist = Wrapped1DDist(candidate[0], table[s][0]); float ydist = Wrapped1DDist(candidate[1], table[s][1]); float d2 = xdist*xdist + ydist*ydist; sampleDist2 = min(sampleDist2, d2); } } } // Keep this sample if it is the best one so far if (sampleDist2 > maxDist2) { maxDist2 = sampleDist2; table[currentSample][0] = candidate[0]; table[currentSample][1] = candidate[1]; } } addSampleToGrid(table, currentSample, grid); progress.Update(); } progress.Done(); }
bool HomogeneousVolumeDensity::SampleDirection(const Point &p, const Vector& wi, Vector& wo, float* pdf, RNG &rng) const { const Point Pobj = WorldToVolume(p); if(extent.Inside(Pobj)) { wo = SampleHG(wi, g, rng.RandomFloat(), rng.RandomFloat()); *pdf = PhaseHG(wi, wo, g); return true; } else { return false; } }
int main(int argc, char **argv) { if (argc != 3) { cout << endl << "input format: sobol N D FILENAME" << endl << endl; cout << "The program prints the first N sobol points in D dimensions." << endl; cout << "The points are generated in graycode order." << endl; cout << "The primitive polynomials and initial direction numbers are" << endl << "given by the input file FILENAME." << endl << endl; return 0; } int N = atoi(argv[1]); HenyeyGreensteinSampleGenerator hg(N); RNG rng; rng.Seed(3); vector<vector<SobolPoints3D *>> mpVec2nd; for(int i = 0 ; i < 10 ; i++) { vector<SobolPoints3D *> *mpVec = new vector<SobolPoints3D *>(); for(int j = 0 ; j < 5 ; j++) { float wPrev[3]; for(int k = 0 ; k < 3 ; k++) wPrev[k] = rng.RandomFloat(); Vector _wPrev(wPrev[0], wPrev[1], wPrev[2]); _wPrev.Normalize(); wPrev[0] = _wPrev.x; wPrev[1] = _wPrev.y; wPrev[2] = _wPrev.z; SobolPoints3D * mp = new SobolPoints3D(wPrev[0], wPrev[1], wPrev[2], 0.f); mpVec ->push_back(mp); } mpVec2nd.push_back(*mpVec); } vector<vector<SobolPoints3D *>> transformedPaths; Vector z(1.f,-1.f,1.5f); z.Normalize(); // when z = (0, 1, 0), it will cause some problem! hg.TransformVector(z, mpVec2nd, transformedPaths); vector<SobolPoints3D *> paths; vector<SobolPoints3D *> pathsConverted; for(int i = 0 ; i < 20 ; i++) { SobolPoints3D * sp = new SobolPoints3D(rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat()); Vector v(sp ->operator Vector()); v.Normalize(); sp ->x = v.x; sp ->y = v.y; sp ->z = v.z; paths.push_back(sp); } hg.TransformVector(z, paths, pathsConverted); //hg.PrintVectors(transformedPaths); hg.ToString(z, mpVec2nd, transformedPaths); //hg.ToString(z, paths, pathsConverted); // Later, make sure that I free the one dimensional vectors then 2 dimensional vectors. You must loop over the vector<vector<MediaPath *>>. }
Ray Persp::UnProject(int U, int V, RNG &rng){ Ray result; /*Vec centerOfPixel = leftBottomVP + Vec(U*xDelta,V*yDelta,0) + Vec(xDelta/2.0f,yDelta/2.0f,.0f);*/ float epsilon1 = rng.RandomFloat(); float epsilon2 = rng.RandomFloat(); Vec targetPoint = leftBottomVP + Vec(U*xDelta,V*yDelta,0) + Vec( epsilon1*xDelta, epsilon2*yDelta,.0f); Vec dir = Vec(targetPoint.x, targetPoint.y, targetPoint.z); dir.norm(); result = Mat4::Mul(this->viewMatInv,Ray(targetPoint, dir)); return result; }
// Sampling Function Definitions void StratifiedSample1D(float *samp, int nSamples, RNG &rng, bool jitter) { float invTot = 1.f / nSamples; for (int i = 0; i < nSamples; ++i) { float delta = jitter ? rng.RandomFloat() : 0.5f; *samp++ = (i + delta) * invTot; } }
Spectrum UniformSampleOneLight(const Scene *scene, const Renderer *renderer, MemoryArena &arena, const Point &p, const Normal &n, const Vector &wo, float rayEpsilon, float time, BSDF *bsdf, const Sample *sample, RNG &rng, int lightNumOffset, const LightSampleOffsets *lightSampleOffset, const BSDFSampleOffsets *bsdfSampleOffset) { // Randomly choose a single light to sample, _light_ int nLights = int(scene->lights.size()); if (nLights == 0) return Spectrum(0.); int lightNum; if (lightNumOffset != -1) lightNum = Floor2Int(sample->oneD[lightNumOffset][0] * nLights); else lightNum = Floor2Int(rng.RandomFloat() * nLights); lightNum = min(lightNum, nLights-1); Light *light = scene->lights[lightNum]; // Initialize light and bsdf samples for single light sample LightSample lightSample; BSDFSample bsdfSample; if (lightSampleOffset != NULL && bsdfSampleOffset != NULL) { lightSample = LightSample(sample, *lightSampleOffset, 0); bsdfSample = BSDFSample(sample, *bsdfSampleOffset, 0); } else { lightSample = LightSample(rng); bsdfSample = BSDFSample(rng); } return (float)nLights * EstimateDirect(scene, renderer, arena, light, p, n, wo, rayEpsilon, time, bsdf, rng, lightSample, bsdfSample, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)); }
static inline void mutate(RNG &rng, float *v, float min = 0.f, float max = 1.f) { if (min == max) { *v = min; return; } Assert(min < max); float s1 = 1.f / 1024.f, s2 = 1.f / 64.f; static const float negLogRatio = -logf(s2/s1); float delta = (max - min) * s2 * expf(negLogRatio * rng.RandomFloat()); if (rng.RandomFloat() < 0.5f) { *v += delta; if (*v > max) *v = min + (*v - max); } else { *v -= delta; if (*v < min) *v = max - (min - *v); } Assert(*v >= min && *v <= max); }
Spectrum EmissionIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Sample *sample, RNG &rng, Spectrum *T, MemoryArena &arena) const { VolumeRegion *vr = scene->volumeRegion; Assert(sample != NULL); float t0, t1; if (!vr || !vr->IntersectP(ray, &t0, &t1) || (t1-t0) == 0.f) { *T = Spectrum(1.f); return 0.f; } // Do emission-only volume integration in _vr_ Spectrum Lv(0.); // Prepare for volume integration stepping int nSamples = Ceil2Int((t1-t0) / stepSize); float step = (t1 - t0) / nSamples; Spectrum Tr(1.f); pbrt::Point p = ray(t0), pPrev; Vector w = -ray.d; t0 += sample->oneD[scatterSampleOffset][0] * step; for (int i = 0; i < nSamples; ++i, t0 += step) { // Advance to sample at _t0_ and update _T_ pPrev = p; p = ray(t0); Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth); Spectrum stepTau = vr->tau(tauRay, .5f * stepSize, rng.RandomFloat()); Tr *= Exp(-stepTau); // Possibly terminate ray marching if transmittance is small if (Tr.y() < 1e-3) { const float continueProb = .5f; if (rng.RandomFloat() > continueProb) { Tr = 0.f; break; } Tr /= continueProb; } // Compute emission-only source term at _p_ Lv += Tr * vr->Lve(p, w, ray.time); } *T = Tr; return Lv * step; }
static inline void mutate(RNG &rng, float *v, float min = 0.f, float max = 1.f) { if (min == max) { *v = min; return; } Assert(min < max); float a = 1.f / 1024.f, b = 1.f / 64.f; static const float logRatio = -logf(b/a); float delta = (max - min) * b * expf(logRatio * rng.RandomFloat()); if (rng.RandomFloat() < 0.5f) { *v += delta; if (*v >= max) *v = min + (*v - max); } else { *v -= delta; if (*v < min) *v = max - (min - *v); } if (*v < min || *v >= max) *v = min; }
// Monte Carlo Function Definitions void RejectionSampleDisk(float *x, float *y, RNG &rng) { float sx, sy; do { sx = 1.f - 2.f * rng.RandomFloat(); sy = 1.f - 2.f * rng.RandomFloat(); } while (sx*sx + sy*sy > 1.f); *x = sx; *y = sy; }
void StratifiedSample2D(float *samp, int nx, int ny, RNG &rng, bool jitter) { float dx = 1.f / nx, dy = 1.f / ny; for (int y = 0; y < ny; ++y) for (int x = 0; x < nx; ++x) { float jx = jitter ? rng.RandomFloat() : 0.5f; float jy = jitter ? rng.RandomFloat() : 0.5f; *samp++ = (x + jx) * dx; *samp++ = (y + jy) * dy; } }
Spectrum VSDScatteringIntegrator::LiSingle(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Sample *sample, RNG &rng, Spectrum *T, MemoryArena &arena) const { VolumeRegion *vr = scene->volumeRegion; float t0, t1; vr->IntersectP(ray, &t0, &t1); // Do single scattering volume integration in _vr_ Spectrum Lv(0.); // Prepare for volume integration stepping int nSamples = Ceil2Int((t1-t0) / stepSize); float step = (t1 - t0) / nSamples; Spectrum Tr(1.f); Point p = ray(t0), pPrev; t0 += sample->oneD[scatterSampleOffset][0] * step; // Compute the emission from the voxels, not from the light sources for (int i = 0; i < nSamples; ++i, t0 += step) { // Advance to sample at _t0_ and update _T_ pPrev = p; p = ray(t0); Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth); Spectrum stepTau = vr->tau(tauRay, .5f * stepSize, rng.RandomFloat()); Tr *= Exp(-stepTau); // Possibly terminate ray marching if transmittance is small if (Tr.y() < 1e-3) { const float continueProb = .5f; if (rng.RandomFloat() > continueProb) { Tr = 0.f; break; } Tr /= continueProb; } // Compute emission term at _p_ Lv += Tr * vr->PhotonDensity(p); } *T = Tr; return Lv * step; }
//both rays have to be normalized + the vrl.mint is beginning of the media and vrl.maxt is the end of interraction. h will contain the smallest distance between the vectors float sampleVRL(const Ray &r,const Ray &vrl, RNG& rng, float &h){ float uh; //closest point parameter on camera ray float vh; //closest point parameter on vrl h=ln2lnPP(r, vrl, uh, vh); float phi=acosf(Dot(r.d, vrl.d)); float v0d= vrl.mint-vh; float v1d= vrl.maxt-vh; float rnd=rng.RandomFloat(); return invSqrCDF(rnd, phi, h, v0d, v1d); }
void Gen_UniformHemisphere(BSDF* bsdf, const Vector & wo, Vector* wi, float* pdf, Spectrum* f) { float u1 = rng.RandomFloat(); float u2 = rng.RandomFloat(); Vector wiL = UniformSampleHemisphere(u1, u2); *wi = bsdf->LocalToWorld(wiL); *pdf = UniformHemispherePdf(); *f = bsdf->f(wo, *wi); }
void Gen_CosHemisphere(BSDF* bsdf, const Vector & wo, Vector* wi, float* pdf, Spectrum* f) { float u1 = rng.RandomFloat(); float u2 = rng.RandomFloat(); Vector wiL = CosineSampleHemisphere(u1, u2); *wi = bsdf->LocalToWorld(wiL); float cosTheta = wiL.z; *pdf = CosineHemispherePdf(cosTheta, u2); *f = bsdf->f(wo, *wi); }
void AggregateTest::Render(const Scene *scene) { RNG rng; ProgressReporter prog(nIterations, "Aggregate Test"); // Compute bounding box of region used to generate random rays BBox bbox = scene->WorldBound(); bbox.Expand(bbox.pMax[bbox.MaximumExtent()] - bbox.pMin[bbox.MaximumExtent()]); Point lastHit; float lastEps = 0.f; for (int i = 0; i < nIterations; ++i) { // Choose random rays, _rayAccel_ and _rayAll_ for testing // Choose ray origin for testing accelerator Point org(Lerp(rng.RandomFloat(), bbox.pMin.x, bbox.pMax.x), Lerp(rng.RandomFloat(), bbox.pMin.y, bbox.pMax.y), Lerp(rng.RandomFloat(), bbox.pMin.z, bbox.pMax.z)); if ((rng.RandomUInt() % 4) == 0) org = lastHit; // Choose ray direction for testing accelerator Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); if ((rng.RandomUInt() % 32) == 0) dir.x = dir.y = 0.f; else if ((rng.RandomUInt() % 32) == 0) dir.x = dir.z = 0.f; else if ((rng.RandomUInt() % 32) == 0) dir.y = dir.z = 0.f; // Choose ray epsilon for testing accelerator float eps = 0.f; if (rng.RandomFloat() < .25) eps = lastEps; else if (rng.RandomFloat() < .25) eps = 1e-3f; Ray rayAccel(org, dir, eps); Ray rayAll = rayAccel; // Compute intersections using accelerator and exhaustive testing Intersection isectAccel, isectAll; bool hitAccel = scene->Intersect(rayAccel, &isectAccel); bool hitAll = false; bool inconsistentBounds = false; for (u_int j = 0; j < primitives.size(); ++j) { if (bboxes[j].IntersectP(rayAll)) hitAll |= primitives[j]->Intersect(rayAll, &isectAll); else if (primitives[j]->Intersect(rayAll, &isectAll)) inconsistentBounds = true; } // Report any inconsistencies between intersections if (!inconsistentBounds && ((hitAccel != hitAll) || (rayAccel.maxt != rayAll.maxt))) Warning("Disagreement: t accel %.16g [%a] t exhaustive %.16g [%a]\n" "Ray: org [%a, %a, %a], dir [%a, %a, %a], mint = %a", rayAccel.maxt, rayAll.maxt, rayAccel.maxt, rayAll.maxt, rayAll.o.x, rayAll.o.y, rayAll.o.z, rayAll.d.x, rayAll.d.y, rayAll.d.z, rayAll.mint); if (hitAll) { lastHit = rayAll(rayAll.maxt); lastEps = isectAll.RayEpsilon; } prog.Update(); } prog.Done(); }
int RandomSampler::GetMoreSamples(Sample *sample, RNG &rng) { if (samplePos == nSamples) { if (xPixelStart == xPixelEnd || yPixelStart == yPixelEnd) return 0; if (++xPos == xPixelEnd) { xPos = xPixelStart; ++yPos; } if (yPos == yPixelEnd) return 0; for (int i = 0; i < 5 * nSamples; ++i) imageSamples[i] = rng.RandomFloat(); // Shift image samples to pixel coordinates for (int o = 0; o < 2 * nSamples; o += 2) { imageSamples[o] += xPos; imageSamples[o+1] += yPos; } samplePos = 0; } // Return next \mono{RandomSampler} sample point sample->imageX = imageSamples[2*samplePos]; sample->imageY = imageSamples[2*samplePos+1]; sample->lensU = lensSamples[2*samplePos]; sample->lensV = lensSamples[2*samplePos+1]; sample->time = Lerp(timeSamples[samplePos], shutterOpen, shutterClose); // Generate stratified samples for integrators for (uint32_t i = 0; i < sample->n1D.size(); ++i) for (uint32_t j = 0; j < sample->n1D[i]; ++j) sample->oneD[i][j] = rng.RandomFloat(); for (uint32_t i = 0; i < sample->n2D.size(); ++i) for (uint32_t j = 0; j < 2*sample->n2D[i]; ++j) sample->twoD[i][j] = rng.RandomFloat(); ++samplePos; return 1; }
Spectrum IrradianceCacheIntegrator::pathL(Ray &r, const Scene *scene, const Renderer *renderer, RNG &rng, MemoryArena &arena) const { Spectrum L(0.f); Spectrum pathThroughput = 1.; RayDifferential ray(r); bool specularBounce = false; for (int pathLength = 0; ; ++pathLength) { // Find next vertex of path Intersection isect; if (!scene->Intersect(ray, &isect)) break; if (pathLength == 0) r.maxt = ray.maxt; pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena); // Possibly add emitted light at path vertex if (specularBounce) L += pathThroughput * isect.Le(-ray.d); // Evaluate BSDF at hit point BSDF *bsdf = isect.GetBSDF(ray, arena); // Sample illumination from lights to find path contribution const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Vector wo = -ray.d; L += pathThroughput * UniformSampleOneLight(scene, renderer, arena, p, n, wo, isect.rayEpsilon, ray.time, bsdf, NULL, rng); if (pathLength+1 == maxIndirectDepth) break; // Sample BSDF to get new path direction // Get random numbers for sampling new direction, \mono{bs1}, \mono{bs2}, and \mono{bcs} Vector wi; float pdf; BxDFType flags; Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng), &pdf, BSDF_ALL, &flags); if (f.IsBlack() || pdf == 0.) break; specularBounce = (flags & BSDF_SPECULAR) != 0; pathThroughput *= f * AbsDot(wi, n) / pdf; ray = RayDifferential(p, wi, ray, isect.rayEpsilon); // Possibly terminate the path if (pathLength > 2) { float rrProb = min(1.f, pathThroughput.y()); if (rng.RandomFloat() > rrProb) break; pathThroughput /= rrProb; } } return L; }
void LatinHypercube(float *samples, u_int nSamples, u_int nDim, RNG &rng) { // Generate LHS samples along diagonal float delta = 1.f / nSamples; for (u_int i = 0; i < nSamples; ++i) for (u_int j = 0; j < nDim; ++j) samples[nDim * i + j] = (i + (rng.RandomFloat())) * delta; // Permute LHS samples in each dimension for (u_int i = 0; i < nDim; ++i) { for (u_int j = 0; j < nSamples; ++j) { u_int other = j + (rng.RandomUInt() % (nSamples - j)); swap(samples[nDim * j + i], samples[nDim * other + i]); } } }
Spectrum SingleScatteringFluorescenceRWLIntegrator::Transmittance(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Sample *sample, RNG &rng, MemoryArena &arena) const { if (!scene->volumeRegion) return Spectrum(1.f); float step, offset; if (sample) { step = stepSize; offset = sample->oneD[tauSampleOffset][0]; } else { step = 4.f * stepSize; offset = rng.RandomFloat(); } Spectrum tau = scene->volumeRegion->tau(ray, step, offset); return Exp(-tau); }
static void LargeStep(RNG &rng, MLTSample *sample, int maxDepth, int x0, int x1, int y0, int y1, float t0, float t1) { sample->cameraSample.imageX = Lerp(rng.RandomFloat(), x0, x1); sample->cameraSample.imageY = Lerp(rng.RandomFloat(), y0, y1); sample->cameraSample.time = Lerp(rng.RandomFloat(), t0, t1); sample->cameraSample.lensU = rng.RandomFloat(); sample->cameraSample.lensV = rng.RandomFloat(); for (int i = 0; i < maxDepth; ++i) { // Apply large step to $i$th _PathSample_ PathSample &ps = sample->pathSamples[i]; ps.bsdfComponent = rng.RandomFloat(); ps.bsdfDir0 = rng.RandomFloat(); ps.bsdfDir1 = rng.RandomFloat(); ps.bsdfLightComponent = rng.RandomFloat(); ps.bsdfLightDir0 = rng.RandomFloat(); ps.bsdfLightDir1 = rng.RandomFloat(); ps.lightNum0 = rng.RandomFloat(); ps.lightNum1 = rng.RandomFloat(); ps.lightDir0 = rng.RandomFloat(); ps.lightDir1 = rng.RandomFloat(); } }
Spectrum VolumePatIntegrator::UniformSampleLight(const Scene *scene, const Renderer *renderer, MemoryArena &arena, const Point &p, const Normal &n, const Vector &wo, float rayEpsilon, float time, RNG &rng) const { // Randomly choose a single light to sample, _light_ int nLights = int(scene->lights.size()); if (nLights == 0) return Spectrum(0.); int lightNum; lightNum = Floor2Int(rng.RandomFloat() * nLights); lightNum = min(lightNum, nLights-1); Light *light = scene->lights[lightNum]; // Initialize light sample for single light sampling LightSample lightSample(rng); return (float) nLights * EstimateDirectLight(scene, renderer, arena, light, p, n, wo, rayEpsilon, time, rng, lightSample); }
bool HomogeneousVolumeDensity::SampleDistance(const Ray &ray, float *tDist, Point &Psample, float *pdf, RNG &rng, const int &wl) const { // Compute the sampling step Vector w = -ray.d; float t = -log(1 - rng.RandomFloat()) / Sigma_t(ray.o, w, ray.time, wl); *tDist = ray.mint + t; Psample = ray(t); if (!extent.Inside(Psample)) { return false; } else { // Compute the PDF that is associated with this sample float extenctionCoeff = Sigma_t(Psample, w, ray.time, wl); float samplePdf = extenctionCoeff * exp(-extenctionCoeff * t); *pdf = samplePdf; return true; } }
Spectrum SingleScatteringFluorescenceRWLIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Sample *sample, RNG &rng, Spectrum *T, MemoryArena &arena) const { VolumeRegion *vr = scene->volumeRegion; float t0, t1; if (!vr || !vr->IntersectP(ray, &t0, &t1) || (t1-t0) == 0.f) { *T = 1.f; return 0.f; } // Do single scattering volume integration in _vr_ Spectrum Lv(0.); // Prepare for volume integration stepping int nSamples = Ceil2Int((t1-t0) / stepSize); float step = (t1 - t0) / nSamples; Spectrum Tr(1.f); Point p = ray(t0), pPrev; Vector w = -ray.d; t0 += sample->oneD[scatterSampleOffset][0] * step; // Compute sample patterns for single scattering samples float *lightNum = arena.Alloc<float>(nSamples); LDShuffleScrambled1D(1, nSamples, lightNum, rng); float *lightComp = arena.Alloc<float>(nSamples); LDShuffleScrambled1D(1, nSamples, lightComp, rng); float *lightPos = arena.Alloc<float>(2*nSamples); LDShuffleScrambled2D(1, nSamples, lightPos, rng); uint32_t sampOffset = 0; for (int i = 0; i < nSamples; ++i, t0 += step) { // Advance to sample at _t0_ and update _T_ pPrev = p; p = ray(t0); Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth); Spectrum stepTau = vr->tau(tauRay, 0.5f * stepSize, rng.RandomFloat()); Tr *= Exp(-stepTau); // Possibly terminate ray marching if transmittance is small if (Tr.y() < 1e-3) { const float continueProb = .5f; if (rng.RandomFloat() > continueProb) { Tr = 0.f; break; } Tr /= continueProb; } // Compute fluorescence emission Spectrum sigma = vr->Mu(p, w, ray.time); if (!sigma.IsBlack() && scene->lights.size() > 0) { int nLights = scene->lights.size(); int ln = min(Floor2Int(lightNum[sampOffset] * nLights), nLights-1); Light *light = scene->lights[ln]; // Add contribution of _light_ due to the in-scattering at _p_ float pdf; VisibilityTester vis; Vector wo; LightSample ls(lightComp[sampOffset], lightPos[2*sampOffset], lightPos[2*sampOffset+1]); Spectrum L = light->Sample_L(p, 0.f, ls, ray.time, &wo, &pdf, &vis); if (!L.IsBlack() && pdf > 0.f && vis.Unoccluded(scene)) { Spectrum Ld = L * vis.Transmittance(scene, renderer, NULL, rng, arena); int lambdaExcIndex = light->GetLaserWavelengthIndex(); float Lpower = Ld.GetLaserEmissionPower(lambdaExcIndex); float yield = vr->Yeild(Point()); Spectrum fEx = vr->fEx(Point()); Spectrum fEm = vr->fEm(Point()); float scale = fEx.GetSampleValueAtWavelengthIndex(lambdaExcIndex); Lv += Lpower * Tr * sigma * vr->p(p, w, -wo, ray.time) * scale * fEm * yield * float(nLights) / pdf; } } ++sampOffset; } *T = Tr; return Lv * step; }
void IGIIntegrator::Preprocess(const Scene *scene, const Camera *camera, const Renderer *renderer) { if (scene->lights.size() == 0) return; MemoryArena arena; RNG rng; // Compute samples for emitted rays from lights vector<float> lightNum(nLightPaths * nLightSets); vector<float> lightSampPos(2 * nLightPaths * nLightSets, 0.f); vector<float> lightSampComp(nLightPaths * nLightSets, 0.f); vector<float> lightSampDir(2 * nLightPaths * nLightSets, 0.f); LDShuffleScrambled1D(nLightPaths, nLightSets, &lightNum[0], rng); LDShuffleScrambled2D(nLightPaths, nLightSets, &lightSampPos[0], rng); LDShuffleScrambled1D(nLightPaths, nLightSets, &lightSampComp[0], rng); LDShuffleScrambled2D(nLightPaths, nLightSets, &lightSampDir[0], rng); // Precompute information for light sampling densities Distribution1D *lightDistribution = ComputeLightSamplingCDF(scene); for (uint32_t s = 0; s < nLightSets; ++s) { for (uint32_t i = 0; i < nLightPaths; ++i) { // Follow path _i_ from light to create virtual lights int sampOffset = s*nLightPaths + i; // Choose light source to trace virtual light path from float lightPdf; int ln = lightDistribution->SampleDiscrete(lightNum[sampOffset], &lightPdf); Light *light = scene->lights[ln]; // Sample ray leaving light source for virtual light path RayDifferential ray; float pdf; LightSample ls(lightSampPos[2*sampOffset], lightSampPos[2*sampOffset+1], lightSampComp[sampOffset]); Normal Nl; Spectrum alpha = light->Sample_L(scene, ls, lightSampDir[2*sampOffset], lightSampDir[2*sampOffset+1], camera->shutterOpen, &ray, &Nl, &pdf); if (pdf == 0.f || alpha.IsBlack()) continue; alpha /= pdf * lightPdf; Intersection isect; while (scene->Intersect(ray, &isect) && !alpha.IsBlack()) { // Create virtual light and sample new ray for path alpha *= renderer->Transmittance(scene, RayDifferential(ray), NULL, rng, arena); Vector wo = -ray.d; BSDF *bsdf = isect.GetBSDF(ray, arena); // Create virtual light at ray intersection point Spectrum contrib = alpha * bsdf->rho(wo, rng) / M_PI; virtualLights[s].push_back(VirtualLight(isect.dg.p, isect.dg.nn, contrib, isect.rayEpsilon)); // Sample new ray direction and update weight for virtual light path Vector wi; float pdf; BSDFSample bsdfSample(rng); Spectrum fr = bsdf->Sample_f(wo, &wi, bsdfSample, &pdf); if (fr.IsBlack() || pdf == 0.f) break; Spectrum contribScale = fr * AbsDot(wi, bsdf->dgShading.nn) / pdf; // Possibly terminate virtual light path with Russian roulette float rrProb = min(1.f, contribScale.y()); if (rng.RandomFloat() > rrProb) break; alpha *= contribScale / rrProb; ray = RayDifferential(isect.dg.p, wi, ray, isect.rayEpsilon); } arena.FreeAll(); } } delete lightDistribution; }
Spectrum IGIIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Intersection &isect, const Sample *sample, RNG &rng, MemoryArena &arena) const { Spectrum L(0.); Vector wo = -ray.d; // Compute emitted light if ray hit an area light source L += isect.Le(wo); // Evaluate BSDF at hit point BSDF *bsdf = isect.GetBSDF(ray, arena); const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; L += UniformSampleAllLights(scene, renderer, arena, p, n, wo, isect.rayEpsilon, ray.time, bsdf, sample, rng, lightSampleOffsets, bsdfSampleOffsets); // Compute indirect illumination with virtual lights uint32_t lSet = min(uint32_t(sample->oneD[vlSetOffset][0] * nLightSets), nLightSets-1); for (uint32_t i = 0; i < virtualLights[lSet].size(); ++i) { const VirtualLight &vl = virtualLights[lSet][i]; // Compute virtual light's tentative contribution _Llight_ float d2 = DistanceSquared(p, vl.p); Vector wi = Normalize(vl.p - p); float G = AbsDot(wi, n) * AbsDot(wi, vl.n) / d2; G = min(G, gLimit); Spectrum f = bsdf->f(wo, wi); if (G == 0.f || f.IsBlack()) continue; Spectrum Llight = f * G * vl.pathContrib / nLightPaths; RayDifferential connectRay(p, wi, ray, isect.rayEpsilon, sqrtf(d2) * (1.f - vl.rayEpsilon)); Llight *= renderer->Transmittance(scene, connectRay, NULL, rng, arena); // Possibly skip virtual light shadow ray with Russian roulette if (Llight.y() < rrThreshold) { float continueProbability = .1f; if (rng.RandomFloat() > continueProbability) continue; Llight /= continueProbability; } // Add contribution from _VirtualLight_ _vl_ if (!scene->IntersectP(connectRay)) L += Llight; } if (ray.depth < maxSpecularDepth) { // Do bias compensation for bounding geometry term int nSamples = (ray.depth == 0) ? nGatherSamples : 1; for (int i = 0; i < nSamples; ++i) { Vector wi; float pdf; BSDFSample bsdfSample = (ray.depth == 0) ? BSDFSample(sample, gatherSampleOffset, i) : BSDFSample(rng); Spectrum f = bsdf->Sample_f(wo, &wi, bsdfSample, &pdf, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)); if (!f.IsBlack() && pdf > 0.f) { // Trace ray for bias compensation gather sample float maxDist = sqrtf(AbsDot(wi, n) / gLimit); RayDifferential gatherRay(p, wi, ray, isect.rayEpsilon, maxDist); Intersection gatherIsect; Spectrum Li = renderer->Li(scene, gatherRay, sample, rng, arena, &gatherIsect); if (Li.IsBlack()) continue; // Add bias compensation ray contribution to radiance sum float Ggather = AbsDot(wi, n) * AbsDot(-wi, gatherIsect.dg.nn) / DistanceSquared(p, gatherIsect.dg.p); if (Ggather - gLimit > 0.f && !isinf(Ggather)) { float gs = (Ggather - gLimit) / Ggather; L += f * Li * (AbsDot(wi, n) * gs / (nSamples * pdf)); } } } } if (ray.depth + 1 < maxSpecularDepth) { Vector wi; // Trace rays for specular reflection and refraction L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample, arena); L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample, arena); } return L; }
Spectrum PathIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &r, const Intersection &isect, const Sample *sample, RNG &rng, MemoryArena &arena) const { // Declare common path integration variables Spectrum pathThroughput = 1., L = 0.; RayDifferential ray(r); bool specularBounce = false; Intersection localIsect; const Intersection *isectp = &isect; for (int bounces = 0; ; ++bounces) { // Possibly add emitted light at path vertex if (bounces == 0 || specularBounce) L += pathThroughput * isectp->Le(-ray.d); // Sample illumination from lights to find path contribution BSDF *bsdf = isectp->GetBSDF(ray, arena); const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Vector wo = -ray.d; if (bounces < SAMPLE_DEPTH) L += pathThroughput * UniformSampleOneLight(scene, renderer, arena, p, n, wo, isectp->rayEpsilon, ray.time, bsdf, sample, rng, lightNumOffset[bounces], &lightSampleOffsets[bounces], &bsdfSampleOffsets[bounces]); else L += pathThroughput * UniformSampleOneLight(scene, renderer, arena, p, n, wo, isectp->rayEpsilon, ray.time, bsdf, sample, rng); // Sample BSDF to get new path direction // Get _outgoingBSDFSample_ for sampling new path direction BSDFSample outgoingBSDFSample; if (bounces < SAMPLE_DEPTH) outgoingBSDFSample = BSDFSample(sample, pathSampleOffsets[bounces], 0); else outgoingBSDFSample = BSDFSample(rng); Vector wi; float pdf; BxDFType flags; Spectrum f = bsdf->Sample_f(wo, &wi, outgoingBSDFSample, &pdf, BSDF_ALL, &flags); if (f.IsBlack() || pdf == 0.) break; specularBounce = (flags & BSDF_SPECULAR) != 0; pathThroughput *= f * AbsDot(wi, n) / pdf; ray = RayDifferential(p, wi, ray, isectp->rayEpsilon); // Possibly terminate the path if (bounces > 3) { float continueProbability = min(.5f, pathThroughput.y()); if (rng.RandomFloat() > continueProbability) break; pathThroughput /= continueProbability; } if (bounces == maxDepth) break; // Find next vertex of path if (!scene->Intersect(ray, &localIsect)) { if (specularBounce) for (uint32_t i = 0; i < scene->lights.size(); ++i) L += pathThroughput * scene->lights[i]->Le(ray); break; } if (bounces > 1) pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena); isectp = &localIsect; } return L; }
Spectrum PhotonVolumeIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Sample *sample, RNG &rng, Spectrum *T, MemoryArena &arena) const { VolumeRegion *vr = scene->volumeRegion; RainbowVolume* rv = dynamic_cast<RainbowVolume*>(vr); KdTree<Photon>* volumeMap = photonShooter->volumeMap; float t0, t1; if (!vr || !vr->IntersectP(ray, &t0, &t1) || (t1-t0) == 0.f){ *T = 1.f; return 0.f; } // Do single scattering & photon multiple scattering volume integration in _vr_ Spectrum Lv(0.); // Prepare for volume integration stepping int nSamples = Ceil2Int((t1-t0) / stepSize); float step = (t1 - t0) / nSamples; Spectrum Tr(1.f); Point p = ray(t0), pPrev; Vector w = -ray.d; t0 += sample->oneD[scatterSampleOffset][0] * step; float *lightNum = arena.Alloc<float>(nSamples); LDShuffleScrambled1D(1, nSamples, lightNum, rng); float *lightComp = arena.Alloc<float>(nSamples); LDShuffleScrambled1D(1, nSamples, lightComp, rng); float *lightPos = arena.Alloc<float>(2*nSamples); LDShuffleScrambled2D(1, nSamples, lightPos, rng); int sampOffset = 0; ClosePhoton *lookupBuf = new ClosePhoton[nSamples]; for (int i = 0; i < nSamples; ++i, t0 += step) { // Advance to sample at _t0_ and update _T_ pPrev = p; p = ray(t0); Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth); Spectrum stepTau = vr->tau(tauRay,.5f * stepSize, rng.RandomFloat()); Tr = Exp(-stepTau); // Possibly terminate raymarching if transmittance is small. if (Tr.y() < 1e-3) { const float continueProb = .5f; if (rng.RandomFloat() > continueProb){ Tr = 0.f; break; } Tr /= continueProb; } // Compute single-scattering source term at _p_ & photon mapped MS Spectrum L_i(0.); Spectrum L_d(0.); Spectrum L_ii(0.); // Lv += Tr*vr->Lve(p, w, ray.time); Spectrum ss = vr->sigma_s(p, w, ray.time); Spectrum sa = vr->sigma_a(p, w, ray.time); if (!ss.IsBlack() && scene->lights.size() > 0) { int nLights = scene->lights.size(); int ln = min(Floor2Int(lightNum[sampOffset] * nLights), nLights-1); Light *light = scene->lights[ln]; // Add contribution of _light_ due to scattering at _p_ float pdf; VisibilityTester vis; Vector wo; LightSample ls(lightComp[sampOffset], lightPos[2*sampOffset], lightPos[2*sampOffset+1]); Spectrum L = light->Sample_L(p, 0.f, ls, ray.time, &wo, &pdf, &vis); if (!L.IsBlack() && pdf > 0.f && vis.Unoccluded(scene)) { Spectrum Ld = L * vis.Transmittance(scene,renderer, NULL, rng, arena); if(rv){ L_d = rv->rainbowReflection(Ld, ray.d, wo); } else { L_d = vr->p(p, w, -wo, ray.time) * Ld * float(nLights)/pdf; } } } // Compute 'indirect' in-scattered radiance from photon map if(!rv){ L_ii += LPhoton(volumeMap, nUsed, lookupBuf, w, p, vr, maxDistSquared, ray.time); } // Compute total in-scattered radiance if (sa.y()!=0.0 || ss.y()!=0.0) L_i = L_d + (ss/(sa+ss))*L_ii; else L_i = L_d; Spectrum nLv = (sa*vr->Lve(p,w,ray.time)*step) + (ss*L_i*step) + (Tr * Lv) ; Lv = nLv; sampOffset++; } *T = Tr; return Lv; }
void CreateRadianceProbes::Render(const Scene *scene) { // Compute scene bounds and initialize probe integrators if (bbox.pMin.x > bbox.pMax.x) bbox = scene->WorldBound(); surfaceIntegrator->Preprocess(scene, camera, this); volumeIntegrator->Preprocess(scene, camera, this); Sample *origSample = new Sample(NULL, surfaceIntegrator, volumeIntegrator, scene); // Compute sampling rate in each dimension Vector delta = bbox.pMax - bbox.pMin; int nProbes[3]; for (int i = 0; i < 3; ++i) nProbes[i] = max(1, Ceil2Int(delta[i] / probeSpacing)); // Allocate SH coefficient vector pointers for sample points int count = nProbes[0] * nProbes[1] * nProbes[2]; Spectrum **c_in = new Spectrum *[count]; for (int i = 0; i < count; ++i) c_in[i] = new Spectrum[SHTerms(lmax)]; // Compute random points on surfaces of scene // Create scene bounding sphere to catch rays that leave the scene Point sceneCenter; float sceneRadius; scene->WorldBound().BoundingSphere(&sceneCenter, &sceneRadius); Transform ObjectToWorld(Translate(sceneCenter - Point(0,0,0))); Transform WorldToObject(Inverse(ObjectToWorld)); Reference<Shape> sph = new Sphere(&ObjectToWorld, &WorldToObject, true, sceneRadius, -sceneRadius, sceneRadius, 360.f); Reference<Material> nullMaterial = Reference<Material>(NULL); GeometricPrimitive sphere(sph, nullMaterial, NULL); vector<Point> surfacePoints; uint32_t nPoints = 32768, maxDepth = 32; surfacePoints.reserve(nPoints + maxDepth); Point pCamera = camera->CameraToWorld(camera->shutterOpen, Point(0, 0, 0)); surfacePoints.push_back(pCamera); RNG rng; while (surfacePoints.size() < nPoints) { // Generate random path from camera and deposit surface points Point pray = pCamera; Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); float rayEpsilon = 0.f; for (uint32_t i = 0; i < maxDepth; ++i) { Ray ray(pray, dir, rayEpsilon, INFINITY, time); Intersection isect; if (!scene->Intersect(ray, &isect) && !sphere.Intersect(ray, &isect)) break; surfacePoints.push_back(ray(ray.maxt)); DifferentialGeometry &hitGeometry = isect.dg; pray = isect.dg.p; rayEpsilon = isect.rayEpsilon; hitGeometry.nn = Faceforward(hitGeometry.nn, -ray.d); dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); dir = Faceforward(dir, hitGeometry.nn); } } // Launch tasks to compute radiance probes at sample points vector<Task *> tasks; ProgressReporter prog(count, "Radiance Probes"); for (int i = 0; i < count; ++i) tasks.push_back(new CreateRadProbeTask(i, nProbes, time, bbox, lmax, includeDirectInProbes, includeIndirectInProbes, nIndirSamples, prog, origSample, surfacePoints, scene, this, c_in[i])); EnqueueTasks(tasks); WaitForAllTasks(); for (uint32_t i = 0; i < tasks.size(); ++i) delete tasks[i]; prog.Done(); // Write radiance probe coefficients to file FILE *f = fopen(filename.c_str(), "w"); if (f) { if (fprintf(f, "%d %d %d\n", lmax, includeDirectInProbes?1:0, includeIndirectInProbes?1:0) < 0 || fprintf(f, "%d %d %d\n", nProbes[0], nProbes[1], nProbes[2]) < 0 || fprintf(f, "%f %f %f %f %f %f\n", bbox.pMin.x, bbox.pMin.y, bbox.pMin.z, bbox.pMax.x, bbox.pMax.y, bbox.pMax.z) < 0) { Error("Error writing radiance file \"%s\" (%s)", filename.c_str(), strerror(errno)); exit(1); } for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) { for (int j = 0; j < SHTerms(lmax); ++j) { fprintf(f, " "); if (c_in[i][j].Write(f) == false) { Error("Error writing radiance file \"%s\" (%s)", filename.c_str(), strerror(errno)); exit(1); } fprintf(f, "\n"); } fprintf(f, "\n"); } fclose(f); } for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) delete[] c_in[i]; delete[] c_in; delete origSample; }
static void LargeStep(RNG &rng, MLTSample *sample, int maxDepth, float x, float y, float t0, float t1, bool bidirectional) { // Do large step mutation of _cameraSample_ sample->cameraSample.imageX = x; sample->cameraSample.imageY = y; sample->cameraSample.time = Lerp(rng.RandomFloat(), t0, t1); sample->cameraSample.lensU = rng.RandomFloat(); sample->cameraSample.lensV = rng.RandomFloat(); for (int i = 0; i < maxDepth; ++i) { // Apply large step to $i$th camera _PathSample_ PathSample &cps = sample->cameraPathSamples[i]; cps.bsdfSample.uComponent = rng.RandomFloat(); cps.bsdfSample.uDir[0] = rng.RandomFloat(); cps.bsdfSample.uDir[1] = rng.RandomFloat(); cps.rrSample = rng.RandomFloat(); // Apply large step to $i$th _LightingSample_ LightingSample &ls = sample->lightingSamples[i]; ls.bsdfSample.uComponent = rng.RandomFloat(); ls.bsdfSample.uDir[0] = rng.RandomFloat(); ls.bsdfSample.uDir[1] = rng.RandomFloat(); ls.lightNum = rng.RandomFloat(); ls.lightSample.uComponent = rng.RandomFloat(); ls.lightSample.uPos[0] = rng.RandomFloat(); ls.lightSample.uPos[1] = rng.RandomFloat(); } if (bidirectional) { // Apply large step to bidirectional light samples sample->lightNumSample = rng.RandomFloat(); for (int i = 0; i < 5; ++i) sample->lightRaySamples[i] = rng.RandomFloat(); for (int i = 0; i < maxDepth; ++i) { // Apply large step to $i$th light _PathSample_ PathSample &lps = sample->lightPathSamples[i]; lps.bsdfSample.uComponent = rng.RandomFloat(); lps.bsdfSample.uDir[0] = rng.RandomFloat(); lps.bsdfSample.uDir[1] = rng.RandomFloat(); lps.rrSample = rng.RandomFloat(); } } }