//------------------------------------------------------------------------------------------- // フォトンレイを生成します. //------------------------------------------------------------------------------------------- void genp( Ray* pr, Vector3* f, int i ) { // generate a photon ray from the point light source with QMC (*f) = Vector3( 2500, 2500, 2500 ) * ( D_PI * 4.0 ); // flux auto p = 2.0 * D_PI * halton( 0, i ); auto t = 2.0 * acos( sqrt(1. - halton( 1, i ) )); auto st = sin( t ); pr->dir = Vector3( cos( p ) * st, cos( t ), sin( p ) * st ); pr->pos = Vector3( 50, 60, 85 ); }
int rrglib::sampler_halton<typeparams,NUM_DIMENSIONS> ::sample (state_t **state_sample_out) { if (NUM_DIMENSIONS <= 0) return 0; state_t *state_new = new state_t; double halton_sample[NUM_DIMENSIONS]; halton (halton_sample); // Generate an independent random variable for each axis. for (int i = 0; i < NUM_DIMENSIONS; i++) (*state_new)[i] = support.size[i] * halton_sample[i] - support.size[i]/2.0 + support.center[i]; *state_sample_out = state_new; return 1; }
gretl_matrix *halton_matrix (int m, int r, int offset, int *err) { const int bases[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181 }; gretl_matrix *H; double hij; int i, j, k, n; if (m > 40 || offset < 0 || m <= 0 || r <= 0) { *err = E_DATA; return NULL; } H = gretl_matrix_alloc(m, r); if (H == NULL) { *err = E_ALLOC; return NULL; } /* we'll discard the first @offset elements */ n = r + offset; for (i=0; i<m; i++) { j = 0; for (k=1; k<n; k++) { hij = halton(k, bases[i]); if (k >= offset) { gretl_matrix_set(H, i, j++, hij); } } } return H; }
void PhotonShootingTask::Run() { // Declare local variables for _PhotonShootingTask_ MemoryArena arena; RNG rng(31 * taskNum); vector<Photon> localDirectPhotons, localIndirectPhotons, localCausticPhotons; vector<RadiancePhoton> localRadiancePhotons; uint32_t totalPaths = 0; bool causticDone = (integrator->nCausticPhotonsWanted == 0); bool indirectDone = (integrator->nIndirectPhotonsWanted == 0); PermutedHalton halton(6, rng); vector<Spectrum> localRpReflectances, localRpTransmittances; while (true) { // Follow photon paths for a block of samples const uint32_t blockSize = 4096; for (uint32_t i = 0; i < blockSize; ++i) { float u[6]; halton.Sample(++totalPaths, u); // Choose light to shoot photon from float lightPdf; int lightNum = lightDistribution->SampleDiscrete(u[0], &lightPdf); const Light *light = scene->lights[lightNum]; // Generate _photonRay_ from light source and initialize _alpha_ RayDifferential photonRay; float pdf; LightSample ls(u[1], u[2], u[3]); Normal Nl; Spectrum Le = light->Sample_L(scene, ls, u[4], u[5], time, &photonRay, &Nl, &pdf); if (pdf == 0.f || Le.IsBlack()) continue; Spectrum alpha = (AbsDot(Nl, photonRay.d) * Le) / (pdf * lightPdf); if (!alpha.IsBlack()) { // Follow photon path through scene and record intersections PBRT_PHOTON_MAP_STARTED_RAY_PATH(&photonRay, &alpha); bool specularPath = true; Intersection photonIsect; int nIntersections = 0; while (scene->Intersect(photonRay, &photonIsect)) { ++nIntersections; // Handle photon/surface intersection alpha *= renderer->Transmittance(scene, photonRay, NULL, rng, arena); BSDF *photonBSDF = photonIsect.GetBSDF(photonRay, arena); BxDFType specularType = BxDFType(BSDF_REFLECTION | BSDF_TRANSMISSION | BSDF_SPECULAR); bool hasNonSpecular = (photonBSDF->NumComponents() > photonBSDF->NumComponents(specularType)); Vector wo = -photonRay.d; if (hasNonSpecular) { // Deposit photon at surface Photon photon(photonIsect.dg.p, alpha, wo); bool depositedPhoton = false; if (specularPath && nIntersections > 1) { if (!causticDone) { PBRT_PHOTON_MAP_DEPOSITED_CAUSTIC_PHOTON(&photonIsect.dg, &alpha, &wo); depositedPhoton = true; localCausticPhotons.push_back(photon); } } else { // Deposit either direct or indirect photon // stop depositing direct photons once indirectDone is true; don't // want to waste memory storing too many if we're going a long time // trying to get enough caustic photons desposited. if (nIntersections == 1 && !indirectDone && integrator->finalGather) { PBRT_PHOTON_MAP_DEPOSITED_DIRECT_PHOTON(&photonIsect.dg, &alpha, &wo); depositedPhoton = true; localDirectPhotons.push_back(photon); } else if (nIntersections > 1 && !indirectDone) { PBRT_PHOTON_MAP_DEPOSITED_INDIRECT_PHOTON(&photonIsect.dg, &alpha, &wo); depositedPhoton = true; localIndirectPhotons.push_back(photon); } } // Possibly create radiance photon at photon intersection point if (depositedPhoton && integrator->finalGather && rng.RandomFloat() < .125f) { Normal n = photonIsect.dg.nn; n = Faceforward(n, -photonRay.d); localRadiancePhotons.push_back(RadiancePhoton(photonIsect.dg.p, n)); Spectrum rho_r = photonBSDF->rho(rng, BSDF_ALL_REFLECTION); localRpReflectances.push_back(rho_r); Spectrum rho_t = photonBSDF->rho(rng, BSDF_ALL_TRANSMISSION); localRpTransmittances.push_back(rho_t); } } if (nIntersections >= integrator->maxPhotonDepth) break; // Sample new photon ray direction Vector wi; float pdf; BxDFType flags; Spectrum fr = photonBSDF->Sample_f(wo, &wi, BSDFSample(rng), &pdf, BSDF_ALL, &flags); if (fr.IsBlack() || pdf == 0.f) break; Spectrum anew = alpha * fr * AbsDot(wi, photonBSDF->dgShading.nn) / pdf; // Possibly terminate photon path with Russian roulette float continueProb = min(1.f, anew.y() / alpha.y()); if (rng.RandomFloat() > continueProb) break; alpha = anew / continueProb; specularPath &= ((flags & BSDF_SPECULAR) != 0); if (indirectDone && !specularPath) break; photonRay = RayDifferential(photonIsect.dg.p, wi, photonRay, photonIsect.rayEpsilon); } PBRT_PHOTON_MAP_FINISHED_RAY_PATH(&photonRay, &alpha); } arena.FreeAll(); } // Merge local photon data with data in _PhotonIntegrator_ { MutexLock lock(mutex); // Give up if we're not storing enough photons if (abortTasks) return; if (nshot > 500000 && (unsuccessful(integrator->nCausticPhotonsWanted, causticPhotons.size(), blockSize) || unsuccessful(integrator->nIndirectPhotonsWanted, indirectPhotons.size(), blockSize))) { Error("Unable to store enough photons. Giving up.\n"); causticPhotons.erase(causticPhotons.begin(), causticPhotons.end()); indirectPhotons.erase(indirectPhotons.begin(), indirectPhotons.end()); radiancePhotons.erase(radiancePhotons.begin(), radiancePhotons.end()); abortTasks = true; return; } progress.Update(localIndirectPhotons.size() + localCausticPhotons.size()); nshot += blockSize; // Merge indirect photons into shared array if (!indirectDone) { integrator->nIndirectPaths += blockSize; for (uint32_t i = 0; i < localIndirectPhotons.size(); ++i) indirectPhotons.push_back(localIndirectPhotons[i]); localIndirectPhotons.erase(localIndirectPhotons.begin(), localIndirectPhotons.end()); if (indirectPhotons.size() >= integrator->nIndirectPhotonsWanted) indirectDone = true; nDirectPaths += blockSize; for (uint32_t i = 0; i < localDirectPhotons.size(); ++i) directPhotons.push_back(localDirectPhotons[i]); localDirectPhotons.erase(localDirectPhotons.begin(), localDirectPhotons.end()); } // Merge direct, caustic, and radiance photons into shared array if (!causticDone) { integrator->nCausticPaths += blockSize; for (uint32_t i = 0; i < localCausticPhotons.size(); ++i) causticPhotons.push_back(localCausticPhotons[i]); localCausticPhotons.erase(localCausticPhotons.begin(), localCausticPhotons.end()); if (causticPhotons.size() >= integrator->nCausticPhotonsWanted) causticDone = true; } for (uint32_t i = 0; i < localRadiancePhotons.size(); ++i) radiancePhotons.push_back(localRadiancePhotons[i]); localRadiancePhotons.erase(localRadiancePhotons.begin(), localRadiancePhotons.end()); for (uint32_t i = 0; i < localRpReflectances.size(); ++i) rpReflectances.push_back(localRpReflectances[i]); localRpReflectances.erase(localRpReflectances.begin(), localRpReflectances.end()); for (uint32_t i = 0; i < localRpTransmittances.size(); ++i) rpTransmittances.push_back(localRpTransmittances[i]); localRpTransmittances.erase(localRpTransmittances.begin(), localRpTransmittances.end()); } // Exit task if enough photons have been found if (indirectDone && causticDone) break; } }
//------------------------------------------------------------------------------------------- // レイを追跡します. //------------------------------------------------------------------------------------------- void trace( const Ray &r, int dpt, bool m, const Vector3 &fl, const Vector3 &adj, int i ) { double t; int id; dpt++; if (!intersect(r, t, id) || (dpt >= 20)) return; auto d3 = dpt * 3; const auto &obj = sph[ id ]; auto x = r.pos + r.dir*t, n = normalize( x - obj.pos ); auto f = obj.color; auto nl = ( dot(n, r.dir ) < 0 ) ? n : n*-1; auto p = ( f.x > f.y && f.x > f.z ) ? f.x : ( f.y > f.z ) ? f.y : f.z; if ( obj.type == MaterialType::Matte ) { if (m) { // eye ray // store the measurment point auto hp = new HitRecord; hp->f = mul(f,adj); hp->pos = x; hp->nrm = n; hp->idx = i; hitpoints.push_back( hp ); // find the bounding box of all the measurement points hpbbox.merge( x ); } else { // photon ray // find neighboring measurement points and accumulate flux via progressive density estimation auto hh = (x - hpbbox.mini) * hash_s; auto ix = abs(int(hh.x)); auto iy = abs(int(hh.y)); auto iz = abs(int(hh.z)); // strictly speaking, we should use #pragma omp critical here. // it usually works without an artifact due to the fact that photons are // rarely accumulated to the same measurement points at the same time (especially with QMC). // it is also significantly faster. { auto list = hash_grid[ hash( ix, iy, iz ) ]; for( auto itr = list.begin(); itr != list.end(); itr++ ) { auto hp = (*itr); auto v = hp->pos - x; // check normals to be closer than 90 degree (avoids some edge brightning) if ((dot(hp->nrm,n) > 1e-3) && (dot(v,v) <= hp->r2)) { // unlike N in the paper, hp->n stores "N / ALPHA" to make it an integer value auto g = (hp->n * ALPHA + ALPHA ) / ( hp->n * ALPHA + 1.0 ); hp->r2 = hp->r2 * g; hp->n++; hp->flux = ( hp->flux + mul( hp->f, fl ) / D_PI ) * g; } } } // use QMC to sample the next direction auto r1 = 2.0 * D_PI * halton( d3 - 1, i ); auto r2 = halton( d3 + 0, i ); auto r2s = sqrt( r2 ); auto w = nl; auto u = normalize(cross((fabs(w.x) > .1 ? Vector3(0, 1, 0) : Vector3(1, 0, 0)), w)); auto v = cross( w, u ); auto d = normalize( u * cos( r1 ) * r2s + v * sin( r1 ) * r2s + w * sqrt( 1 - r2 )); if ( halton( d3 + 1, i ) < p ) trace(Ray(x, d), dpt, m, mul(f,fl)*(1. / p), mul(f, adj), i); } } else if ( obj.type == MaterialType::Mirror ) { trace(Ray(x, reflect(r.dir, n)), dpt, m, mul(f,fl), mul(f,adj), i); } else { Ray lr( x, reflect( r.dir, n ) ); auto into = dot(n, nl ) > 0.0; auto nc = 1.0; auto nt = 1.5; auto nnt = (into) ? nc / nt : nt / nc; auto ddn = dot( r.dir, nl ); auto cos2t = 1 - nnt * nnt * ( 1 - ddn * ddn ); // total internal reflection if (cos2t < 0) return trace(lr, dpt, m, mul(f, fl), mul(f, adj), i); auto td = normalize(r.dir * nnt - n * ( ( into ? 1 : -1 ) * ( ddn * nnt + sqrt( cos2t )))); auto a = nt - nc; auto b = nt + nc; auto R0 = a * a / ( b * b ); auto c = 1 - (into ? -ddn : dot(td, n)); auto Re = R0 + (1 - R0) * c * c * c * c * c; auto P = Re; Ray rr(x, td); auto fa = mul( f, adj ); auto ffl = mul( f, fl ); if (m) { // eye ray (trace both rays) trace( lr, dpt, m, ffl, fa * Re, i ); trace( rr, dpt, m, ffl, fa * (1.0 - Re), i ); } else { // photon ray (pick one via Russian roulette) ( halton( d3 - 1, i ) < P ) ? trace( lr, dpt, m, ffl, fa * Re, i ) : trace( rr, dpt, m, ffl, fa * (1.0 - Re), i ); } } }
void LightShootingTask::Run() { // tady by mel byt kod z photon mappingu MemoryArena arena; uint32_t totalPaths = 0; RNG rng(seed); PermutedHalton halton(6, rng); while (true) { // Follow photon paths for a block of samples const uint32_t blockSize = 4096; for (uint32_t i = 0; i < blockSize; ++i) { float u[6]; halton.Sample(++totalPaths, u); // Choose light to shoot photon from float lightPdf; int lightNum = lightDistribution->SampleDiscrete(u[0], &lightPdf); const Light *light = scene->lights[lightNum]; // Generate _photonRay_ from light source and initialize _alpha_ RayDifferential photonRay; float pdf; LightSample ls(u[1], u[2], u[3]); Normal Nl; Spectrum Le = light->Sample_L(scene, ls, u[4], u[5],time, &photonRay, &Nl, &pdf); if (pdf == 0.f || Le.IsBlack()) continue; Spectrum alpha = (AbsDot(Nl, photonRay.d) * Le) / (pdf * lightPdf); if (!alpha.IsBlack()) { // Follow photon path through scene and record intersections PBRT_PHOTON_MAP_STARTED_RAY_PATH(&photonRay, &alpha); bool specularPath = true; Intersection photonIsect; int nIntersections = 0; while (scene->Intersect(photonRay, &photonIsect)) { ++nIntersections; //MC tady by mel byt i kod pro volumetriku // Handle photon/surface intersection // alpha *= renderer->Transmittance(scene, photonRay, NULL, rng, arena); BSDF *photonBSDF = photonIsect.GetBSDF(photonRay, arena); Vector wo = -photonRay.d; //MC tady se ukladaly photony takze tady bych mel ukladat samples do filmu kamery // // Deposit photon at surface //Photon photon(photonIsect.dg.p, alpha, wo); //tuhle metodu chci pouzit //filmAddSample() if (nIntersections >= maxDepth) break; // Sample new photon ray direction Vector wi; float pdf; BxDFType flags; Spectrum fr = photonBSDF->Sample_f(wo, &wi, BSDFSample(rng), &pdf, BSDF_ALL, &flags); if (fr.IsBlack() || pdf == 0.f) break; Spectrum anew = alpha * fr * AbsDot(wi, photonBSDF->dgShading.nn) / pdf; // Possibly terminate photon path with Russian roulette float continueProb = min(1.f, anew.y() / alpha.y()); if (rng.RandomFloat() > continueProb) break; alpha = anew / continueProb; specularPath &= ((flags & BSDF_SPECULAR) != 0); photonRay = RayDifferential(photonIsect.dg.p, wi, photonRay, photonIsect.rayEpsilon); } PBRT_PHOTON_MAP_FINISHED_RAY_PATH(&photonRay, &alpha); } arena.FreeAll(); } //termination criteria ??? if (totalPaths==maxPathCount) { break; } } }