bool GridAccel::IntersectP(const Ray &ray) const { if (!gridForRefined) { // NOBOOK rayTests.Add(0, 1); // NOBOOK rayHits.Add(0, 1); // NOBOOK } // NOBOOK int rayId = ++curMailboxId; // Check ray against overall grid bounds float rayT; if (bounds.Inside(ray(ray.mint))) rayT = ray.mint; else if (!bounds.IntersectP(ray, &rayT)) return false; Point gridIntersect = ray(rayT); // Set up 3D DDA for ray float NextCrossingT[3], DeltaT[3]; int Step[3], Out[3], Pos[3]; for (int axis = 0; axis < 3; ++axis) { // Compute current voxel for axis Pos[axis] = PosToVoxel(gridIntersect, axis); if (ray.d[axis] >= 0) { // Handle ray with positive direction for voxel stepping NextCrossingT[axis] = rayT + (VoxelToPos(Pos[axis]+1, axis) - gridIntersect[axis]) / ray.d[axis]; DeltaT[axis] = Width[axis] / ray.d[axis]; Step[axis] = 1; Out[axis] = NVoxels[axis]; } else { // Handle ray with negative direction for voxel stepping NextCrossingT[axis] = rayT + (VoxelToPos(Pos[axis], axis) - gridIntersect[axis]) / ray.d[axis]; DeltaT[axis] = -Width[axis] / ray.d[axis]; Step[axis] = -1; Out[axis] = -1; } } // Walk grid for shadow ray for (;;) { int offset = Offset(Pos[0], Pos[1], Pos[2]); Voxel *voxel = voxels[offset]; if (voxel && voxel->IntersectP(ray, rayId)) return true; // Advance to next voxel // Find _stepAxis_ for stepping to next voxel int bits = ((NextCrossingT[0] < NextCrossingT[1]) << 2) + ((NextCrossingT[0] < NextCrossingT[2]) << 1) + ((NextCrossingT[1] < NextCrossingT[2])); const int cmpToAxis[8] = { 2, 1, 2, 1, 2, 2, 0, 0 }; int stepAxis = cmpToAxis[bits]; if (ray.maxt < NextCrossingT[stepAxis]) break; Pos[stepAxis] += Step[stepAxis]; if (Pos[stepAxis] == Out[stepAxis]) break; NextCrossingT[stepAxis] += DeltaT[stepAxis]; } return false; }
Spectrum ExPhotonIntegrator::LPhoton( KdTree<Photon, PhotonProcess> *map, int nPaths, int nLookup, BSDF *bsdf, const Intersection &isect, const Vector &wo, float maxDistSquared) { Spectrum L(0.); if (!map) return L; BxDFType nonSpecular = BxDFType(BSDF_REFLECTION | BSDF_TRANSMISSION | BSDF_DIFFUSE | BSDF_GLOSSY); if (bsdf->NumComponents(nonSpecular) == 0) return L; static StatsCounter lookups("Photon Map", "Total lookups"); // NOBOOK // Initialize _PhotonProcess_ object, _proc_, for photon map lookups PhotonProcess proc(nLookup, isect.dg.p); proc.photons = (ClosePhoton *)alloca(nLookup * sizeof(ClosePhoton)); // Do photon map lookup ++lookups; // NOBOOK map->Lookup(isect.dg.p, proc, maxDistSquared); // Accumulate light from nearby photons static StatsRatio foundRate("Photon Map", "Photons found per lookup"); // NOBOOK foundRate.Add(proc.foundPhotons, 1); // NOBOOK // Estimate reflected light from photons ClosePhoton *photons = proc.photons; int nFound = proc.foundPhotons; Normal Nf = Dot(wo, bsdf->dgShading.nn) < 0 ? -bsdf->dgShading.nn : bsdf->dgShading.nn; if (bsdf->NumComponents(BxDFType(BSDF_REFLECTION | BSDF_TRANSMISSION | BSDF_GLOSSY)) > 0) { // Compute exitant radiance from photons for glossy surface for (int i = 0; i < nFound; ++i) { const Photon *p = photons[i].photon; BxDFType flag = Dot(Nf, p->wi) > 0.f ? BSDF_ALL_REFLECTION : BSDF_ALL_TRANSMISSION; float k = kernel(p, isect.dg.p, maxDistSquared); L += (k / nPaths) * bsdf->f(wo, p->wi, flag) * p->alpha; } } else { // Compute exitant radiance from photons for diffuse surface Spectrum Lr(0.), Lt(0.); for (int i = 0; i < nFound; ++i) { if (Dot(Nf, photons[i].photon->wi) > 0.f) { float k = kernel(photons[i].photon, isect.dg.p, maxDistSquared); Lr += (k / nPaths) * photons[i].photon->alpha; } else { float k = kernel(photons[i].photon, isect.dg.p, maxDistSquared); Lt += (k / nPaths) * photons[i].photon->alpha; } } L += Lr * bsdf->rho(wo, BSDF_ALL_REFLECTION) * INV_PI + Lt * bsdf->rho(wo, BSDF_ALL_TRANSMISSION) * INV_PI; } return L; }
bool Voxel::Intersect(const Ray &ray, Intersection *isect, int rayId) { // Refine primitives in voxel if needed if (!allCanIntersect) { MailboxPrim **mpp; if (nPrimitives == 1) mpp = &onePrimitive; else mpp = primitives; for (u_int i = 0; i < nPrimitives; ++i) { MailboxPrim *mp = mpp[i]; // Refine primitive in _mp_ if it's not intersectable if (!mp->primitive->CanIntersect()) { vector<Reference<Primitive> > p; mp->primitive->FullyRefine(p); Assert(p.size() > 0); // NOBOOK if (p.size() == 1) mp->primitive = p[0]; else mp->primitive = new GridAccel(p, true, false); } } allCanIntersect = true; } // Loop over primitives in voxel and find intersections bool hitSomething = false; MailboxPrim **mpp; if (nPrimitives == 1) mpp = &onePrimitive; else mpp = primitives; for (u_int i = 0; i < nPrimitives; ++i) { MailboxPrim *mp = mpp[i]; // Do mailbox check between ray and primitive if (mp->lastMailboxId == rayId) continue; // Check for ray--primitive intersection mp->lastMailboxId = rayId; rayTests.Add(1, 0); // NOBOOK if (mp->primitive->Intersect(ray, isect)) { rayHits.Add(1, 0); // NOBOOK hitSomething = true; } } return hitSomething; }
bool IrradianceCache::InterpolateIrradiance(const Scene *scene, const Point &p, const Normal &n, Spectrum *E) const { if (!octree) return false; IrradProcess proc(n, maxError); octree->Lookup(p, proc); // Update irradiance cache lookup statistics static StatsPercentage nSuccessfulLookups("Irradiance Cache", "Successful irradiance cache lookups"); static StatsRatio nSamplesFound("Irradiance Cache", "Irradiance samples found per successful lookup"); static StatsRatio nSamplesChecked("Irradiance Cache", "Irradiance samples checked per lookup"); nSuccessfulLookups.Add(proc.Successful() ? 1 : 0, 1); nSamplesFound.Add(proc.nFound, 1); nSamplesChecked.Add(proc.samplesChecked, 1); if (!proc.Successful()) return false; *E = proc.GetIrradiance(); return true; }
// GridAccel Method Definitions GridAccel::GridAccel(const vector<Reference<Primitive> > &p, bool forRefined, bool refineImmediately) : gridForRefined(forRefined) { // Initialize _prims_ with primitives for grid vector<Reference<Primitive> > prims; if (refineImmediately) for (u_int i = 0; i < p.size(); ++i) p[i]->FullyRefine(prims); else prims = p; // Initialize mailboxes for grid nMailboxes = prims.size(); mailboxes = (MailboxPrim *)AllocAligned(nMailboxes * sizeof(MailboxPrim)); for (u_int i = 0; i < nMailboxes; ++i) new (&mailboxes[i]) MailboxPrim(prims[i]); // Compute bounds and choose grid resolution for (u_int i = 0; i < prims.size(); ++i) bounds = Union(bounds, prims[i]->WorldBound()); Vector delta = bounds.pMax - bounds.pMin; // Find _voxelsPerUnitDist_ for grid int maxAxis = bounds.MaximumExtent(); float invMaxWidth = 1.f / delta[maxAxis]; Assert(invMaxWidth > 0.f); // NOBOOK float cubeRoot = 3.f * powf(float(prims.size()), 1.f/3.f); float voxelsPerUnitDist = cubeRoot * invMaxWidth; for (int axis = 0; axis < 3; ++axis) { NVoxels[axis] = Round2Int(delta[axis] * voxelsPerUnitDist); NVoxels[axis] = Clamp(NVoxels[axis], 1, 64); } // Compute voxel widths and allocate voxels for (int axis = 0; axis < 3; ++axis) { Width[axis] = delta[axis] / NVoxels[axis]; InvWidth[axis] = (Width[axis] == 0.f) ? 0.f : 1.f / Width[axis]; } int nVoxels = NVoxels[0] * NVoxels[1] * NVoxels[2]; voxels = (Voxel **)AllocAligned(nVoxels * sizeof(Voxel *)); memset(voxels, 0, nVoxels * sizeof(Voxel *)); // Add primitives to grid voxels for (u_int i = 0; i < prims.size(); ++i) { // Find voxel extent of primitive BBox pb = prims[i]->WorldBound(); int vmin[3], vmax[3]; for (int axis = 0; axis < 3; ++axis) { vmin[axis] = PosToVoxel(pb.pMin, axis); vmax[axis] = PosToVoxel(pb.pMax, axis); } // Add primitive to overlapping voxels for (int z = vmin[2]; z <= vmax[2]; ++z) for (int y = vmin[1]; y <= vmax[1]; ++y) for (int x = vmin[0]; x <= vmax[0]; ++x) { int offset = Offset(x, y, z); if (!voxels[offset]) { // Allocate new voxel and store primitive in it voxels[offset] = new (voxelArena) Voxel(&mailboxes[i]); } else { // Add primitive to already-allocated voxel voxels[offset]->AddPrimitive(&mailboxes[i]); } } static StatsRatio nPrimitiveVoxels("Grid Accelerator", // NOBOOK "Voxels covered vs # / primitives"); // NOBOOK nPrimitiveVoxels.Add((1 + vmax[0]-vmin[0]) * (1 + vmax[1]-vmin[1]) * // NOBOOK (1 + vmax[2]-vmin[2]), 1); // NOBOOK } // Update grid statistics static StatsPercentage nEmptyVoxels("Grid Accelerator", "Empty voxels"); static StatsRatio avgPrimsInVoxel("Grid Accelerator", "Average # of primitives in voxel"); static StatsCounter maxPrimsInVoxel("Grid Accelerator", "Max # of primitives in a grid voxel"); nEmptyVoxels.Add(0, NVoxels[0] * NVoxels[1] * NVoxels[2]); avgPrimsInVoxel.Add(0,NVoxels[0] * NVoxels[1] * NVoxels[2]); for (int z = 0; z < NVoxels[2]; ++z) for (int y = 0; y < NVoxels[1]; ++y) for (int x = 0; x < NVoxels[0]; ++x) { int offset = Offset(x, y, z); if (!voxels[offset]) nEmptyVoxels.Add(1, 0); else { int nPrims = voxels[offset]->nPrimitives; maxPrimsInVoxel.Max(nPrims); avgPrimsInVoxel.Add(nPrims, 0); } } }