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(); }
void SurfacePointsRenderer::Render(const Scene &scene) { // Declare shared variables for Poisson point generation BBox octBounds = scene.WorldBound(); octBounds.Expand(.001f * powf(octBounds.Volume(), 1.f/3.f)); Octree<SurfacePoint> pointOctree(octBounds); // 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); Material nullMaterial; GeometricPrimitive sphere(sph, nullMaterial, NULL); int maxFails = 2000, repeatedFails = 0, maxRepeatedFails = 0; if (PbrtOptions.quickRender) maxFails = max(10, maxFails / 10); int totalPathsTraced = 0, totalRaysTraced = 0, numPointsAdded = 0; ProgressReporter prog(maxFails, "Depositing samples"); // Launch tasks to trace rays to find Poisson points PBRT_SUBSURFACE_STARTED_RAYS_FOR_POINTS(); vector<Task *> tasks; RWMutex *mutex = RWMutex::Create(); int nTasks = NumSystemCores(); for (int i = 0; i < nTasks; ++i) tasks.push_back(new SurfacePointTask(scene, pCamera, time, i, minDist, maxFails, *mutex, repeatedFails, maxRepeatedFails, totalPathsTraced, totalRaysTraced, numPointsAdded, sphere, pointOctree, points, prog)); EnqueueTasks(tasks); WaitForAllTasks(); for (uint32_t i = 0; i < tasks.size(); ++i) delete tasks[i]; RWMutex::Destroy(mutex); prog.Done(); PBRT_SUBSURFACE_FINISHED_RAYS_FOR_POINTS(totalRaysTraced, numPointsAdded); if (filename != "") { // Write surface points to file FILE *f = fopen(filename.c_str(), "w"); if (!f) { Error("Unable to open output file \"%s\" (%s)", filename.c_str(), strerror(errno)); return; } fprintf(f, "# points generated by SurfacePointsRenderer\n"); fprintf(f, "# position (x,y,z), normal (x,y,z), area, rayEpsilon\n"); for (u_int i = 0; i < points.size(); ++i) { const SurfacePoint &sp = points[i]; fprintf(f, "%g %g %g %g %g %g %g %g\n", sp.p.x, sp.p.y, sp.p.z, sp.n.x, sp.n.y, sp.n.z, sp.area, sp.rayEpsilon); } fclose(f); } }
BBox OrthoCamera::Bounds() const { BBox orig_bound(Point(-1, -1, 0), Point(1, 1, 0)); // TODO - improve this BBox bound; for (int i = 1024; i >= 0; i--) { // ugly hack, but last thing we do is to sample StartTime, so should be ok const_cast<OrthoCamera*>(this)->SampleMotion(Lerp(static_cast<float>(i) / 1024.f, CameraMotion.StartTime(), CameraMotion.EndTime())); bound = Union(bound, ScreenToWorld * orig_bound); } bound.Expand(max(1.f, MachineEpsilon::E(bound))); return bound; }
TEST_F(BBoxTest, ExpandByNegativeValueWorks) { BBox b (Point (1, 1, 1), Point (4, 4, 4)); float delta = -1.0; b.Expand (delta); EXPECT_EQ (2, b.pMin.x); EXPECT_EQ (2, b.pMin.y); EXPECT_EQ (2, b.pMin.z); EXPECT_EQ (3, b.pMax.x); EXPECT_EQ (3, b.pMax.y); EXPECT_EQ (3, b.pMax.z); }
TEST_F(BBoxTest, ExpandByPositiveValueWorks) { BBox b (Point (2, 2, 2), Point (3, 3, 3)); float delta = 1.0; b.Expand (delta); EXPECT_EQ (1, b.pMin.x); EXPECT_EQ (1, b.pMin.y); EXPECT_EQ (1, b.pMin.z); EXPECT_EQ (4, b.pMax.x); EXPECT_EQ (4, b.pMax.y); EXPECT_EQ (4, b.pMax.z); }
void HitPoints::Init() { // Not using UpdateBBox() because hp->accumPhotonRadius2 is not yet set BBox hpBBox = BBox(); for (u_int i = 0; i < (*hitPoints).size(); ++i) { HitPoint *hp = &(*hitPoints)[i]; if (hp->IsSurface()) hpBBox = Union(hpBBox, hp->GetPosition()); } // Calculate initial radius Vector ssize = hpBBox.pMax - hpBBox.pMin; initialPhotonRadius = renderer->sppmi->photonStartRadiusScale * ((ssize.x + ssize.y + ssize.z) / 3.f) / sqrtf(nSamplePerPass) * 2.f; const float photonRadius2 = initialPhotonRadius * initialPhotonRadius; // Expand the bounding box by used radius hpBBox.Expand(initialPhotonRadius); // Update hit points information hitPointBBox = hpBBox; maxHitPointRadius2 = photonRadius2; LOG(LUX_DEBUG, LUX_NOERROR) << "Hit points bounding box: " << hitPointBBox; LOG(LUX_DEBUG, LUX_NOERROR) << "Hit points max. radius: " << sqrtf(maxHitPointRadius2); // Initialize hit points field for (u_int i = 0; i < (*hitPoints).size(); ++i) { HitPoint *hp = &(*hitPoints)[i]; hp->accumPhotonRadius2 = photonRadius2; } // Allocate hit points lookup accelerator switch (renderer->sppmi->lookupAccelType) { case HASH_GRID: lookUpAccel = new HashGrid(this); break; case KD_TREE: lookUpAccel = new KdTree(this); break; case HYBRID_HASH_GRID: lookUpAccel = new HybridHashGrid(this); break; case PARALLEL_HASH_GRID: lookUpAccel = new ParallelHashGrid(this, renderer->sppmi->parallelHashGridSpare); break; default: assert (false); } }
BBox PerspectiveCamera::Bounds() const { float lensr = max(LensRadius, 0.f); BBox orig_bound(Point(-lensr, -lensr, 0.f), Point(lensr, lensr, 0.f)); // TODO - improve this BBox bound; for (int i = 1024; i >= 0; i--) { // ugly hack, but last thing we do is to sample StartTime, so should be ok const_cast<PerspectiveCamera*>(this)->SampleMotion(Lerp(static_cast<float>(i) / 1024.f, CameraMotion.StartTime(), CameraMotion.EndTime())); bound = Union(bound, CameraToWorld * orig_bound); } bound.Expand(max(1.f, MachineEpsilon::E(bound))); return bound; }
void Worker::InitRadius(uint iteration) { BBox* hitPointsbbox = GetHostBBox(); Vector ssize = hitPointsbbox->pMax - hitPointsbbox->pMin; float photonRadius = ((ssize.x + ssize.y + ssize.z) / 3.f) / ((engine->width * engine->superSampling + engine->height * engine->superSampling) / 2.f) * 2.f; float photonRadius2 = photonRadius * photonRadius; #if defined USE_SPPMPA || defined USE_PPMPA float g = 1; for (uint k = 1; k < iteration; k++) g *= (k + engine->alpha) / k; g /= iteration; photonRadius2 = photonRadius2 * g; //std::cout << "photon_radius: " << photonRadius2 << '\n'; #endif #ifdef REBUILD_HASH // Expand the bounding box by used radius hitPointsbbox->Expand(sqrt(photonRadius2)); #endif // Initialize hit points field //const float photonRadius2 = photonRadius * photonRadius; #if defined USE_SPPMPA || defined USE_PPMPA currentPhotonRadius2 = photonRadius2; #else for (unsigned int i = 0; i < engine->hitPointTotal; ++i) { //HitPointInfo *hpinfo = engine->GetHitPointInfo(i); HitPointRadianceFlux *hp = GetHitPoint(i); hp->accumPhotonRadius2 = photonRadius2; } #endif }