00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 #include "stdafx.h"
00027 #include "renderers/surfacepoints.h"
00028 #include "paramset.h"
00029 #include "octree.h"
00030 #include "camera.h"
00031 #include "probes.h"
00032 #include "parallel.h"
00033 #include "progressreporter.h"
00034 #include "scene.h"
00035 #include "intersection.h"
00036 #include "montecarlo.h"
00037 #include "shapes/sphere.h"
00038 
00039 
00040 class SurfacePointTask : public Task {
00041 public:
00042     SurfacePointTask(const Scene *sc, const Point &org, float ti, int tn,
00043         float msd, int mf, RWMutex &m, int &rf, int &mrf,
00044         int &tpt, int &trt, int &npa, GeometricPrimitive &sph,
00045         Octree<SurfacePoint> &oct, vector<SurfacePoint> &sps,
00046         ProgressReporter &pr)
00047         : taskNum(tn), scene(sc), origin(org), time(ti),
00048           minSampleDist(msd), maxFails(mf), mutex(m),
00049           repeatedFails(rf), maxRepeatedFails(mrf), totalPathsTraced(tpt),
00050           totalRaysTraced(trt), numPointsAdded(npa), sphere(sph),
00051           octree(oct), surfacePoints(sps), prog(pr) { }
00052     void Run();
00053 
00054     int taskNum;
00055     const Scene *scene;
00056     Point origin;
00057     float time;
00058     float minSampleDist;
00059     int maxFails;
00060 
00061     RWMutex &mutex;
00062     int &repeatedFails, &maxRepeatedFails;
00063     int &totalPathsTraced, &totalRaysTraced, &numPointsAdded;
00064     GeometricPrimitive &sphere;
00065     Octree<SurfacePoint> &octree;
00066     vector<SurfacePoint> &surfacePoints;
00067     ProgressReporter &prog;
00068 };
00069 
00070 
00071 struct PoissonCheck {
00072     PoissonCheck(float md, const Point &pt)
00073         { maxDist2 = md * md; failed = false; p = pt; }
00074     float maxDist2;
00075     bool failed;
00076     Point p;
00077     bool operator()(const SurfacePoint &sp) {
00078         if (DistanceSquared(sp.p, p) < maxDist2) {
00079             failed = true; return false;
00080         }
00081         return true;
00082     }
00083 };
00084 
00085 
00086 
00087 
00088 Spectrum SurfacePointsRenderer::Li(const Scene *scene,
00089     const RayDifferential &ray, const Sample *sample, RNG &rng, MemoryArena &arena,
00090     Intersection *isect, Spectrum *T) const {
00091     return 0.f;
00092 }
00093 
00094 
00095 Spectrum SurfacePointsRenderer::Transmittance(const Scene *scene, const RayDifferential &ray,
00096     const Sample *sample, RNG &rng, MemoryArena &arena) const {
00097     return 0.f;
00098 }
00099 
00100 
00101 void SurfacePointsRenderer::Render(const Scene *scene) {
00102     
00103     BBox octBounds = scene->WorldBound();
00104     octBounds.Expand(.001f * powf(octBounds.Volume(), 1.f/3.f));
00105     Octree<SurfacePoint> pointOctree(octBounds);
00106 
00107     
00108     Point sceneCenter;
00109     float sceneRadius;
00110     scene->WorldBound().BoundingSphere(&sceneCenter, &sceneRadius);
00111     Transform ObjectToWorld(Translate(sceneCenter - Point(0,0,0)));
00112     Transform WorldToObject(Inverse(ObjectToWorld));
00113     Reference<Shape> sph = new Sphere(&ObjectToWorld, &WorldToObject,
00114         true, sceneRadius, -sceneRadius, sceneRadius, 360.f);
00115     Reference<Material> nullMaterial = Reference<Material>(NULL);
00116     GeometricPrimitive sphere(sph, nullMaterial, NULL);
00117     int maxFails = 2000, repeatedFails = 0, maxRepeatedFails = 0;
00118     if (PbrtOptions.quickRender) maxFails = max(10, maxFails / 10);
00119     int totalPathsTraced = 0, totalRaysTraced = 0, numPointsAdded = 0;
00120     ProgressReporter prog(maxFails, "Depositing samples");
00121     
00122     PBRT_SUBSURFACE_STARTED_RAYS_FOR_POINTS();
00123     vector<Task *> tasks;
00124     RWMutex *mutex = RWMutex::Create();
00125     int nTasks = NumSystemCores();
00126     for (int i = 0; i < nTasks; ++i)
00127         tasks.push_back(new SurfacePointTask(scene, pCamera, time, i,
00128             minDist, maxFails, *mutex, repeatedFails, maxRepeatedFails,
00129             totalPathsTraced, totalRaysTraced, numPointsAdded, sphere, pointOctree,
00130             points, prog));
00131     EnqueueTasks(tasks);
00132     WaitForAllTasks();
00133     for (uint32_t i = 0; i < tasks.size(); ++i)
00134         delete tasks[i];
00135     RWMutex::Destroy(mutex);
00136     prog.Done();
00137     PBRT_SUBSURFACE_FINISHED_RAYS_FOR_POINTS(totalRaysTraced, numPointsAdded);
00138     if (filename != "") {
00139         
00140         FILE *f = fopen(filename.c_str(), "w");
00141         if (!f) Severe("Unable to open output file \"%s\"", filename.c_str());
00142         fprintf(f, "# points generated by SurfacePointsRenderer\n");
00143         fprintf(f, "# position (x,y,z), normal (x,y,z), area, rayEpsilon\n");
00144         for (u_int i = 0; i < points.size(); ++i) {
00145             const SurfacePoint &sp = points[i];
00146             fprintf(f, "%g %g %g %g %g %g %g %g\n", sp.p.x, sp.p.y, sp.p.z,
00147                 sp.n.x, sp.n.y, sp.n.z, sp.area, sp.rayEpsilon);
00148         }
00149         fclose(f);
00150     }
00151 }
00152 
00153 
00154 void SurfacePointTask::Run() {
00155     
00156     RNG rng(37 * taskNum);
00157     MemoryArena arena;
00158     vector<SurfacePoint> candidates;
00159     while (true) {
00160         int pathsTraced, raysTraced = 0;
00161         for (pathsTraced = 0; pathsTraced < 20000; ++pathsTraced) {
00162             
00163             Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat());
00164             Ray ray(origin, dir, 0.f, INFINITY, time);
00165             while (ray.depth < 30) {
00166                 
00167                 ++raysTraced;
00168                 Intersection isect;
00169                 bool hitOnSphere = false;
00170                 if (!scene->Intersect(ray, &isect)) {
00171                     if (!sphere.Intersect(ray, &isect))
00172                         break;
00173                     hitOnSphere = true;
00174                 }
00175                 DifferentialGeometry &hitGeometry = isect.dg;
00176                 hitGeometry.nn = Faceforward(hitGeometry.nn, -ray.d);
00177 
00178                 
00179                 if (!hitOnSphere && ray.depth >= 3 &&
00180                     isect.GetBSSRDF(RayDifferential(ray), arena) != NULL) {
00181                     float area = M_PI * minSampleDist * minSampleDist;
00182                     candidates.push_back(SurfacePoint(hitGeometry.p, hitGeometry.nn,
00183                                                       area, isect.rayEpsilon));
00184                 }
00185 
00186                 
00187                 Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat());
00188                 dir = Faceforward(dir, hitGeometry.nn);
00189                 ray = Ray(hitGeometry.p, dir, ray, isect.rayEpsilon);
00190             }
00191             arena.FreeAll();
00192         }
00193         
00194         vector<bool> candidateRejected;
00195         candidateRejected.reserve(candidates.size());
00196         RWMutexLock lock(mutex, READ);
00197         for (uint32_t i = 0; i < candidates.size(); ++i) {
00198             PoissonCheck check(minSampleDist, candidates[i].p);
00199             octree.Lookup(candidates[i].p, check);
00200             candidateRejected.push_back(check.failed);
00201         }
00202 
00203         
00204         lock.UpgradeToWrite();
00205         if (repeatedFails >= maxFails)
00206             return;
00207         totalPathsTraced += pathsTraced;
00208         totalRaysTraced += raysTraced;
00209         int oldMaxRepeatedFails = maxRepeatedFails;
00210         for (uint32_t i = 0; i < candidates.size(); ++i) {
00211             if (candidateRejected[i]) {
00212                 
00213                 ++repeatedFails;
00214                 maxRepeatedFails = max(maxRepeatedFails, repeatedFails);
00215                 if (repeatedFails >= maxFails)
00216                     return;
00217             }
00218             else {
00219                 
00220                 SurfacePoint &sp = candidates[i];
00221                 PoissonCheck check(minSampleDist, sp.p);
00222                 octree.Lookup(sp.p, check);
00223                 if (check.failed) {
00224                     
00225                     ++repeatedFails;
00226                     maxRepeatedFails = max(maxRepeatedFails, repeatedFails);
00227                     if (repeatedFails >= maxFails)
00228                         return;
00229                 }
00230                 else {
00231                     ++numPointsAdded;
00232                     repeatedFails = 0;
00233                     Vector delta(minSampleDist, minSampleDist, minSampleDist);
00234                     octree.Add(sp, BBox(sp.p-delta, sp.p+delta));
00235                     PBRT_SUBSURFACE_ADDED_POINT_TO_OCTREE(&sp, minSampleDist);
00236                     surfacePoints.push_back(sp);
00237                 }
00238             }
00239         }
00240 
00241         
00242         if (repeatedFails > oldMaxRepeatedFails) {
00243             int delta = repeatedFails - oldMaxRepeatedFails;
00244             prog.Update(delta);
00245         }
00246         if (totalPathsTraced > 50000 && numPointsAdded == 0) {
00247             Warning("There don't seem to be any objects with BSSRDFs "
00248                     "in this scene.  Giving up.");
00249             return;
00250         }
00251         candidates.erase(candidates.begin(), candidates.end());
00252     }
00253 }
00254 
00255 
00256 void FindPoissonPointDistribution(const Point &pCamera, float time,
00257         float minDist, const Scene *scene, vector<SurfacePoint> *points) {
00258     SurfacePointsRenderer sp(minDist, pCamera, time, "");
00259     sp.Render(scene);
00260     points->swap(sp.points);
00261 }
00262 
00263 
00264 SurfacePointsRenderer *CreateSurfacePointsRenderer(const ParamSet ¶ms,
00265         const Point &pCamera, float time) {
00266     float minDist = params.FindOneFloat("minsampledistance", .25f);
00267     string filename = params.FindOneString("filename", "");
00268     if (PbrtOptions.quickRender) { minDist *= 4.f; }
00269     return new SurfacePointsRenderer(minDist, pCamera, time, filename);
00270 }
00271 
00272