void LDPixelSample(int xPos, int yPos, float shutterOpen, float shutterClose, int nPixelSamples, Sample *samples, float *buf, RNG &rng) { // Prepare temporary array pointers for low-discrepancy camera samples float *imageSamples = buf; buf += 2 * nPixelSamples; float *lensSamples = buf; buf += 2 * nPixelSamples; float *timeSamples = buf; buf += nPixelSamples; // Prepare temporary array pointers for low-discrepancy integrator samples uint32_t count1D = samples[0].n1D.size(); uint32_t count2D = samples[0].n2D.size(); const uint32_t *n1D = count1D > 0 ? &samples[0].n1D[0] : NULL; const uint32_t *n2D = count2D > 0 ? &samples[0].n2D[0] : NULL; float **oneDSamples = ALLOCA(float *, count1D); float **twoDSamples = ALLOCA(float *, count2D); for (uint32_t i = 0; i < count1D; ++i) { oneDSamples[i] = buf; buf += n1D[i] * nPixelSamples; } for (uint32_t i = 0; i < count2D; ++i) { twoDSamples[i] = buf; buf += 2 * n2D[i] * nPixelSamples; } // Generate low-discrepancy pixel samples LDShuffleScrambled2D(1, nPixelSamples, imageSamples, rng); LDShuffleScrambled2D(1, nPixelSamples, lensSamples, rng); LDShuffleScrambled1D(1, nPixelSamples, timeSamples, rng); for (uint32_t i = 0; i < count1D; ++i) LDShuffleScrambled1D(n1D[i], nPixelSamples, oneDSamples[i], rng); for (uint32_t i = 0; i < count2D; ++i) LDShuffleScrambled2D(n2D[i], nPixelSamples, twoDSamples[i], rng); // Initialize _samples_ with computed sample values for (int i = 0; i < nPixelSamples; ++i) { samples[i].imageX = xPos + imageSamples[2*i]; samples[i].imageY = yPos + imageSamples[2*i+1]; samples[i].time = Lerp(timeSamples[i], shutterOpen, shutterClose); samples[i].lensU = lensSamples[2*i]; samples[i].lensV = lensSamples[2*i+1]; // Copy integrator samples into _samples[i]_ for (uint32_t j = 0; j < count1D; ++j) { int startSamp = n1D[j] * i; for (uint32_t k = 0; k < n1D[j]; ++k) samples[i].oneD[j][k] = oneDSamples[j][startSamp+k]; } for (uint32_t j = 0; j < count2D; ++j) { int startSamp = 2 * n2D[j] * i; for (uint32_t k = 0; k < 2*n2D[j]; ++k) samples[i].twoD[j][k] = twoDSamples[j][startSamp+k]; } } }
bool LDSampler::GetNextSample(Sample *sample) { if (!oneDSamples) { // Allocate space for pixel's low-discrepancy sample tables oneDSamples = new float *[sample->n1D.size()]; n1D = sample->n1D.size(); for (u_int i = 0; i < sample->n1D.size(); ++i) oneDSamples[i] = new float[sample->n1D[i] * pixelSamples]; twoDSamples = new float *[sample->n2D.size()]; n2D = sample->n2D.size(); for (u_int i = 0; i < sample->n2D.size(); ++i) twoDSamples[i] = new float[2 * sample->n2D[i] * pixelSamples]; } if (samplePos == pixelSamples) { // Advance to next pixel for low-discrepancy sampling if (++xPos == xPixelEnd) { xPos = xPixelStart; ++yPos; } if (yPos == yPixelEnd) return false; samplePos = 0; // Generate low-discrepancy samples for pixel LDShuffleScrambled2D(1, pixelSamples, imageSamples); LDShuffleScrambled2D(1, pixelSamples, lensSamples); LDShuffleScrambled1D(1, pixelSamples, timeSamples); for (u_int i = 0; i < sample->n1D.size(); ++i) LDShuffleScrambled1D(sample->n1D[i], pixelSamples, oneDSamples[i]); for (u_int i = 0; i < sample->n2D.size(); ++i) LDShuffleScrambled2D(sample->n2D[i], pixelSamples, twoDSamples[i]); } // Copy low-discrepancy samples from tables sample->imageX = xPos + imageSamples[2*samplePos]; sample->imageY = yPos + imageSamples[2*samplePos+1]; sample->time = timeSamples[samplePos]; sample->lensU = lensSamples[2*samplePos]; sample->lensV = lensSamples[2*samplePos+1]; for (u_int i = 0; i < sample->n1D.size(); ++i) { int startSamp = sample->n1D[i] * samplePos; for (u_int j = 0; j < sample->n1D[i]; ++j) sample->oneD[i][j] = oneDSamples[i][startSamp+j]; } for (u_int i = 0; i < sample->n2D.size(); ++i) { int startSamp = 2 * sample->n2D[i] * samplePos; for (u_int j = 0; j < 2*sample->n2D[i]; ++j) sample->twoD[i][j] = twoDSamples[i][startSamp+j]; } ++samplePos; return true; }
int BestCandidateSampler::GetMoreSamples(Sample *sample, RNG &rng) { again: if (tableOffset == SAMPLE_TABLE_SIZE) { // Advance to next best-candidate sample table position tableOffset = 0; if (++xTile > xTileEnd) { xTile = xTileStart; if (++yTile > yTileEnd) return 0; } // Update sample shifts RNG tileRng(xTile + (yTile<<8)); for (int i = 0; i < 3; ++i) sampleOffsets[i] = tileRng.RandomFloat(); } // Compute raster sample from table #define WRAP(x) ((x) > 1 ? ((x)-1) : (x)) sample->imageX = (xTile + sampleTable[tableOffset][0]) * tableWidth; sample->imageY = (yTile + sampleTable[tableOffset][1]) * tableWidth; sample->time = Lerp(WRAP(sampleOffsets[0] + sampleTable[tableOffset][2]), shutterOpen, shutterClose); sample->lensU = WRAP(sampleOffsets[1] + sampleTable[tableOffset][3]); sample->lensV = WRAP(sampleOffsets[2] + sampleTable[tableOffset][4]); // Check sample against crop window, goto _again_ if outside if (sample->imageX < xPixelStart || sample->imageX >= xPixelEnd || sample->imageY < yPixelStart || sample->imageY >= yPixelEnd) { ++tableOffset; goto again; } // Compute integrator samples for best-candidate sample for (uint32_t i = 0; i < sample->n1D.size(); ++i) LDShuffleScrambled1D(sample->n1D[i], 1, sample->oneD[i], rng); for (uint32_t i = 0; i < sample->n2D.size(); ++i) LDShuffleScrambled2D(sample->n2D[i], 1, sample->twoD[i], rng); ++tableOffset; return 1; }
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 SingleScatteringIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Sample *sample, Spectrum *T, MemoryArena &arena) const { VolumeRegion *vr = scene->volumeRegion; float t0, t1; if (!vr || !vr->IntersectP(ray, &t0, &t1)) { *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, *sample->rng); float *lightComp = arena.Alloc<float>(nSamples); LDShuffleScrambled1D(1, nSamples, lightComp, *sample->rng); float *lightPos = arena.Alloc<float>(2*nSamples); LDShuffleScrambled2D(1, nSamples, lightPos, *sample->rng); u_int 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, .5f * stepSize, sample->rng->RandomFloat()); Tr *= Exp(-stepTau); // Possibly terminate ray marching if transmittance is small if (Tr.y() < 1e-3) { const float continueProb = .5f; if (sample->rng->RandomFloat() > continueProb) break; Tr /= continueProb; } // Compute single-scattering source term at _p_ Lv += Tr * vr->Lve(p, w, ray.time); Spectrum ss = vr->sigma_s(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, sample->rng, arena); Lv += Tr * ss * vr->p(p, w, -wo, ray.time) * Ld * float(nLights) / pdf; } } ++sampOffset; } *T = Tr; return Lv * step; }
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 IGIIntegrator::Preprocess(const Scene *scene) { if (scene->lights.size() == 0) return; // Compute samples for emitted rays from lights float *lightNum = new float[nLightPaths * nLightSets]; float *lightSamp0 = new float[2 * nLightPaths * nLightSets]; float *lightSamp1 = new float[2 * nLightPaths * nLightSets]; LDShuffleScrambled1D(nLightPaths, nLightSets, lightNum); LDShuffleScrambled2D(nLightPaths, nLightSets, lightSamp0); LDShuffleScrambled2D(nLightPaths, nLightSets, lightSamp1); // Precompute information for light sampling densities int nLights = int(scene->lights.size()); float *lightPower = (float *)alloca(nLights * sizeof(float)); float *lightCDF = (float *)alloca((nLights+1) * sizeof(float)); for (int i = 0; i < nLights; ++i) lightPower[i] = scene->lights[i]->Power(scene).y(); float totalPower; ComputeStep1dCDF(lightPower, nLights, &totalPower, lightCDF); for (u_int s = 0; s < nLightSets; ++s) { for (u_int i = 0; i < nLightPaths; ++i) { // Follow path _i_ from light to create virtual lights int sampOffset = s*nLightPaths + i; // Choose light source to trace path from float lightPdf; int lNum = Floor2Int(SampleStep1d(lightPower, lightCDF, totalPower, nLights, lightNum[sampOffset], &lightPdf) * nLights); // fprintf(stderr, "samp %f -> num %d\n", lightNum[sampOffset], lNum); Light *light = scene->lights[lNum]; // Sample ray leaving light source RayDifferential ray; float pdf; Spectrum alpha = light->Sample_L(scene, lightSamp0[2*sampOffset], lightSamp0[2*sampOffset+1], lightSamp1[2*sampOffset], lightSamp1[2*sampOffset+1], &ray, &pdf); if (pdf == 0.f || alpha.Black()) continue; alpha /= pdf * lightPdf; // fprintf(stderr, "initial alpha %f, light # %d\n", alpha.y(), lNum); Intersection isect; int nIntersections = 0; while (scene->Intersect(ray, &isect) && !alpha.Black()) { ++nIntersections; alpha *= scene->Transmittance(ray); Vector wo = -ray.d; BSDF *bsdf = isect.GetBSDF(ray); // Create virtual light at ray intersection point static StatsCounter vls("IGI Integrator", "Virtual Lights Created"); //NOBOOK ++vls; //NOBOOK Spectrum Le = alpha * bsdf->rho(wo) / M_PI; // fprintf(stderr, "\tmade light with le y %f\n", Le.y()); virtualLights[s].push_back(VirtualLight(isect.dg.p, isect.dg.nn, Le)); // Sample new ray direction and update weight Vector wi; float pdf; BxDFType flags; Spectrum fr = bsdf->Sample_f(wo, &wi, RandomFloat(), RandomFloat(), RandomFloat(), &pdf, BSDF_ALL, &flags); if (fr.Black() || pdf == 0.f) break; Spectrum anew = alpha * fr * AbsDot(wi, bsdf->dgShading.nn) / pdf; float r = anew.y() / alpha.y(); // fprintf(stderr, "\tr = %f\n", r); if (RandomFloat() > r) break; alpha = anew / r; // fprintf(stderr, "\tnew alpha %f\n", alpha.y()); ray = RayDifferential(isect.dg.p, wi); } BSDF::FreeAll(); } } delete[] lightNum; // NOBOOK delete[] lightSamp0; // NOBOOK delete[] lightSamp1; // NOBOOK }