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