Radiance3 RayTracer::L_scatteredSpecularIndirect(const shared_ptr<Surfel>& surfel, const Vector3& wo, int bouncesLeft, Random& rnd) const{ Radiance3 L(0,0,0); if (bouncesLeft > 0){ G3D::UniversalSurfel::ImpulseArray impulses; //Downcast to universalSurfel to allow getting impulses const shared_ptr<UniversalSurfel>& u = dynamic_pointer_cast<UniversalSurfel>(surfel); debugAssertM(notNull(u), "Encountered a Surfel that was not a UniversalSurfel"); //Find the impulses on the surface u->getImpulses(PathDirection::EYE_TO_SOURCE, wo, impulses); //For each impulses, recursively computed the radiance from that direction for (int i = 0; i < impulses.size(); ++i){ Vector3 wi = impulses[i].direction; Color3 magnitude = impulses[i].magnitude; ++m_stats->indirectRays; L += L_i(surfel->position, wi, bouncesLeft - 1, rnd) * magnitude; } //If we enable path tracing, also cast a random ray from the surfel //Technically it is not SpecularIndirect. But as it is not used often, I'm going to leave it here if (m_settings.enablePathTracing){ Vector3 wi = Vector3::hemiRandom(surfel->shadingNormal, rnd); L += L_i(surfel->position, wi, bouncesLeft - 1, rnd) * surfel->finiteScatteringDensity(wi,wo) * abs(wi.dot(surfel->shadingNormal)); } } return L; }
void RayTracer::traceOnePixel(int x, int y, int threadID) { //used for constructing viewport Vector2 tmp(m_settings.width, m_settings.height); Ray primaryRay; // If one ray per pixel: (kinda debugging mode with blue color for places with no surfel hit if (m_settings.raysPerPixel == 1){ //Get the primary ray from the pixel x,y primaryRay = m_camera->worldRay(x + 0.5f, y + 0.5f, Rect2D(tmp)); //Get the first surfel hit. //Can't call L_i unfortunately because we want the blue background for debugging const shared_ptr<Surfel>& s = RayTracer::castRay(primaryRay, finf(), 0); //If there is a surfel hit, get the direct illumination value and apply to the pixel if (s){ //Call L_scatteredDirect to get direct illumination. Invert primaryRay to get the direction for incident light m_image->set(Point2int32(x,y), L_o(s, -primaryRay.direction(), m_settings.recursiveBounces, *(m_rnd[threadID]))); } else{ //Set the pixels with no surfel hit. Include this line so we could make it a specific color for debug purposes. m_image->set(Point2int32(x,y), Color3(0,0,1)); } } else { Radiance3 L(0,0,0); //If more than one ray, randomly generate required number of rays within the pixel for (int i = 0; i < m_settings.raysPerPixel; ++i){ primaryRay = m_camera->worldRay(x + m_rnd[threadID]->uniform(), y + m_rnd[threadID]->uniform(), Rect2D(tmp)); L += L_i(primaryRay.origin(), primaryRay.direction(), m_settings.recursiveBounces, *(m_rnd[threadID])); } m_image->set(Point2int32(x,y), L/m_settings.raysPerPixel); } }
void exafmm_kernel::L2L(std::vector<real>& CiL, const std::vector<real>& CjL, const std::array<real, NDIM>& dist, const integer N) { std::vector<real> Ynm(FMM_P * FMM_P); real rho, theta, phi; std::vector<real> L_r(N), L_i(N); cart2sph(rho, theta, phi, dist); evalMultipole(rho, theta, phi, Ynm); for (integer j = 0; j != FMM_P; ++j) { for (integer k = 0; k <= j; ++k) { integer jkp = j * j + j + k; integer jkm = j * j + j - k; #pragma vector aligned #pragma simd for (integer i = 0; i != N; ++i) { L_r[i] = L_i[i] = 0.0; } for (integer n = j; n != FMM_P; ++n) { for (integer m = j - n + k; m <= n - j + k; ++m) { const integer nn = n * n + n; const integer nj = (n - j) * ((n - j) + 1); const integer npm = nn + std::abs(m); const integer nmm = nn - std::abs(m); const integer jnpkm = nj + std::abs(m - k); const integer jnmkm = nj - std::abs(m - k); const auto Lj_r = CjL.data() + N * npm; const auto Lj_i = CjL.data() + N * nmm; const real sgn = SGN(m); real tmp = std::pow(-real(1.0), real(std::abs(m) - std::abs(k) - std::abs(m - k)) / 2) * Anm[jnpkm] * Anm[jkp] / Anm[npm]; const real Y_r = Ynm[jnpkm] * tmp; const real Y_i = SGN(m-k) * Ynm[jnmkm] * tmp; #pragma vector aligned #pragma simd for (integer i = 0; i != N; ++i) { COMPLEX_MULT_ADD(L_r[i], L_i[i], Y_r, Y_i, Lj_r[i], sgn * Lj_i[i]); } } } auto Li_r = CiL.data() + N * jkp; auto Li_i = CiL.data() + N * jkm; #pragma vector aligned #pragma simd for (integer i = 0; i != N; ++i) { Li_r[i] = L_r[i]; Li_i[i] = (k == 0) ? L_r[i] : L_i[i]; } } } }
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; }