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/createprobes.h"
00028 #include "shapes/sphere.h"
00029 #include "sh.h"
00030 #include "parallel.h"
00031 #include "scene.h"
00032 #include "progressreporter.h"
00033 #include "camera.h"
00034 #include "intersection.h"
00035 #include "integrator.h"
00036 #include "volume.h"
00037 #include "paramset.h"
00038 #include "montecarlo.h"
00039
00040
00041 class CreateRadProbeTask : public Task {
00042 public:
00043 CreateRadProbeTask(int i, int nProbes[3], float t, const BBox &b, int lmax, bool id,
00044 bool ii, int nindir, ProgressReporter &p, Sample *sample,
00045 const vector<Point> &sp, const Scene *sc, const Renderer *ren, Spectrum *c);
00046 void Run();
00047 private:
00048 int pointNum, nProbes[3];
00049 const BBox &bbox;
00050 int lmax, nIndirSamples;
00051 float time;
00052 ProgressReporter &prog;
00053 bool includeDirectInProbes, includeIndirectInProbes;
00054 Sample *origSample;
00055 const Renderer *renderer;
00056 const Scene *scene;
00057 const vector<Point> &surfacePoints;
00058 Spectrum *c_in;
00059 };
00060
00061
00062
00063
00064 CreateRadianceProbes::CreateRadianceProbes(SurfaceIntegrator *surf,
00065 VolumeIntegrator *vol, const Camera *cam, int lm, float ps, const BBox &b,
00066 int nindir, bool id, bool ii, float t, const string &fn) {
00067 lmax = lm;
00068 probeSpacing = ps;
00069 bbox = b;
00070 filename = fn;
00071 includeDirectInProbes = id;
00072 includeIndirectInProbes = ii;
00073 time = t;
00074 nIndirSamples = nindir;
00075 surfaceIntegrator = surf;
00076 volumeIntegrator = vol;
00077 camera = cam;
00078 }
00079
00080
00081 CreateRadianceProbes::~CreateRadianceProbes() {
00082 delete surfaceIntegrator;
00083 delete volumeIntegrator;
00084 }
00085
00086
00087 Spectrum CreateRadianceProbes::Li(const Scene *scene, const RayDifferential &ray,
00088 const Sample *sample, RNG &rng, MemoryArena &arena, Intersection *isect,
00089 Spectrum *T) const {
00090 Assert(ray.time == sample->time);
00091 Spectrum localT;
00092 if (!T) T = &localT;
00093 Intersection localIsect;
00094 if (!isect) isect = &localIsect;
00095 Assert(!ray.HasNaNs());
00096 Spectrum Lo = 0.f;
00097 if (scene->Intersect(ray, isect))
00098 Lo = surfaceIntegrator->Li(scene, this, ray, *isect, sample, rng, arena);
00099 else {
00100 for (uint32_t i = 0; i < scene->lights.size(); ++i)
00101 Lo += scene->lights[i]->Le(ray);
00102 }
00103 Spectrum Lv = volumeIntegrator->Li(scene, this, ray, sample, rng, T, arena);
00104 return *T * Lo + Lv;
00105 }
00106
00107
00108 Spectrum CreateRadianceProbes::Transmittance(const Scene *scene,
00109 const RayDifferential &ray, const Sample *sample, RNG &rng,
00110 MemoryArena &arena) const {
00111 return volumeIntegrator->Transmittance(scene, this, ray, sample, rng, arena);
00112 }
00113
00114
00115 void CreateRadianceProbes::Render(const Scene *scene) {
00116
00117 if (bbox.pMin.x > bbox.pMax.x)
00118 bbox = scene->WorldBound();
00119 surfaceIntegrator->Preprocess(scene, camera, this);
00120 volumeIntegrator->Preprocess(scene, camera, this);
00121 Sample *origSample = new Sample(NULL, surfaceIntegrator, volumeIntegrator,
00122 scene);
00123
00124
00125 Vector delta = bbox.pMax - bbox.pMin;
00126 int nProbes[3];
00127 for (int i = 0; i < 3; ++i)
00128 nProbes[i] = max(1, Ceil2Int(delta[i] / probeSpacing));
00129
00130
00131 int count = nProbes[0] * nProbes[1] * nProbes[2];
00132 Spectrum **c_in = new Spectrum *[count];
00133 for (int i = 0; i < count; ++i)
00134 c_in[i] = new Spectrum[SHTerms(lmax)];
00135
00136
00137
00138
00139 Point sceneCenter;
00140 float sceneRadius;
00141 scene->WorldBound().BoundingSphere(&sceneCenter, &sceneRadius);
00142 Transform ObjectToWorld(Translate(sceneCenter - Point(0,0,0)));
00143 Transform WorldToObject(Inverse(ObjectToWorld));
00144 Reference<Shape> sph = new Sphere(&ObjectToWorld, &WorldToObject,
00145 true, sceneRadius, -sceneRadius, sceneRadius, 360.f);
00146 Reference<Material> nullMaterial = Reference<Material>(NULL);
00147 GeometricPrimitive sphere(sph, nullMaterial, NULL);
00148 vector<Point> surfacePoints;
00149 uint32_t nPoints = 32768, maxDepth = 32;
00150 surfacePoints.reserve(nPoints + maxDepth);
00151 Point pCamera = camera->CameraToWorld(camera->shutterOpen,
00152 Point(0, 0, 0));
00153 surfacePoints.push_back(pCamera);
00154 RNG rng;
00155 while (surfacePoints.size() < nPoints) {
00156
00157 Point pray = pCamera;
00158 Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat());
00159 float rayEpsilon = 0.f;
00160 for (uint32_t i = 0; i < maxDepth; ++i) {
00161 Ray ray(pray, dir, rayEpsilon, INFINITY, time);
00162
00163 Intersection isect;
00164 if (!scene->Intersect(ray, &isect) &&
00165 !sphere.Intersect(ray, &isect))
00166 break;
00167
00168 surfacePoints.push_back(ray(ray.maxt));
00169
00170 DifferentialGeometry &hitGeometry = isect.dg;
00171 pray = isect.dg.p;
00172 rayEpsilon = isect.rayEpsilon;
00173 hitGeometry.nn = Faceforward(hitGeometry.nn, -ray.d);
00174
00175 dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat());
00176 dir = Faceforward(dir, hitGeometry.nn);
00177 }
00178 }
00179
00180
00181 vector<Task *> tasks;
00182 ProgressReporter prog(count, "Radiance Probes");
00183 for (int i = 0; i < count; ++i)
00184 tasks.push_back(new CreateRadProbeTask(i, nProbes, time,
00185 bbox, lmax, includeDirectInProbes,
00186 includeIndirectInProbes, nIndirSamples,
00187 prog, origSample, surfacePoints,
00188 scene, this, c_in[i]));
00189 EnqueueTasks(tasks);
00190 WaitForAllTasks();
00191 for (uint32_t i = 0; i < tasks.size(); ++i)
00192 delete tasks[i];
00193 prog.Done();
00194
00195
00196 FILE *f = fopen(filename.c_str(), "w");
00197 if (f) {
00198 if (fprintf(f, "%d %d %d\n", lmax, includeDirectInProbes?1:0, includeIndirectInProbes?1:0) < 0 ||
00199 fprintf(f, "%d %d %d\n", nProbes[0], nProbes[1], nProbes[2]) < 0 ||
00200 fprintf(f, "%f %f %f %f %f %f\n", bbox.pMin.x, bbox.pMin.y, bbox.pMin.z,
00201 bbox.pMax.x, bbox.pMax.y, bbox.pMax.z) < 0)
00202 Severe("Error writing radiance file \"%s\"", filename.c_str());
00203 for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) {
00204 for (int j = 0; j < SHTerms(lmax); ++j) {
00205 fprintf(f, " ");
00206 if (c_in[i][j].Write(f) == false)
00207 Severe("Error writing radiance file \"%s\"", filename.c_str());
00208 fprintf(f, "\n");
00209 }
00210 fprintf(f, "\n");
00211 }
00212 fclose(f);
00213 }
00214 for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i)
00215 delete[] c_in[i];
00216 delete[] c_in;
00217 delete origSample;
00218 }
00219
00220
00221 CreateRadProbeTask::CreateRadProbeTask(int pn, int d[3], float t,
00222 const BBox &b, int lm, bool id,
00223 bool ii, int nindir, ProgressReporter &p, Sample *samp,
00224 const vector<Point> &sp, const Scene *sc, const Renderer *ren, Spectrum *c)
00225 : bbox(b), prog(p), surfacePoints(sp) {
00226 pointNum = pn;
00227 lmax = lm;
00228 nIndirSamples = nindir;
00229 time = t;
00230 for (int i = 0; i < 3; ++i) nProbes[i] = d[i];
00231 origSample = samp;
00232 c_in = c;
00233 includeDirectInProbes = id;
00234 includeIndirectInProbes = ii;
00235 scene = sc;
00236 renderer = ren;
00237 }
00238
00239
00240 void CreateRadProbeTask::Run() {
00241
00242 int sx = pointNum % nProbes[0];
00243 int sy = (pointNum / nProbes[0]) % nProbes[1];
00244 int sz = pointNum / (nProbes[0] * nProbes[1]);
00245 Assert(sx >= 0 && sx < nProbes[0]);
00246 Assert(sy >= 0 && sy < nProbes[1]);
00247 Assert(sz >= 0 && sz < nProbes[2]);
00248 float tx0 = float(sx) / nProbes[0], tx1 = float(sx+1) / nProbes[0];
00249 float ty0 = float(sy) / nProbes[1], ty1 = float(sy+1) / nProbes[1];
00250 float tz0 = float(sz) / nProbes[2], tz1 = float(sz+1) / nProbes[2];
00251 BBox b(bbox.Lerp(tx0, ty0, tz0), bbox.Lerp(tx1, ty1, tz1));
00252
00253
00254 RNG rng(pointNum);
00255 Spectrum *c_probe = new Spectrum[SHTerms(lmax)];
00256 MemoryArena arena;
00257 uint32_t nFound = 0, lastVisibleOffset = 0;
00258 for (int i = 0; i < 256; ++i) {
00259 if (nFound == 32) break;
00260
00261
00262
00263 float dx = RadicalInverse(i+1, 2);
00264 float dy = RadicalInverse(i+1, 3);
00265 float dz = RadicalInverse(i+1, 5);
00266 Point p = b.Lerp(dx, dy, dz);
00267
00268
00269 if (scene->IntersectP(Ray(surfacePoints[lastVisibleOffset],
00270 p - surfacePoints[lastVisibleOffset],
00271 1e-4f, 1.f, time))) {
00272 uint32_t j;
00273
00274 for (j = 0; j < surfacePoints.size(); ++j)
00275 if (!scene->IntersectP(Ray(surfacePoints[j], p - surfacePoints[j],
00276 1e-4f, 1.f, time))) {
00277 lastVisibleOffset = j;
00278 break;
00279 }
00280 if (j == surfacePoints.size())
00281 continue;
00282 }
00283 ++nFound;
00284
00285
00286 if (includeDirectInProbes) {
00287 for (int i = 0; i < SHTerms(lmax); ++i)
00288 c_probe[i] = 0.f;
00289 SHProjectIncidentDirectRadiance(p, 0.f, time, arena, scene,
00290 true, lmax, rng, c_probe);
00291 for (int i = 0; i < SHTerms(lmax); ++i)
00292 c_in[i] += c_probe[i];
00293 }
00294
00295 if (includeIndirectInProbes) {
00296 for (int i = 0; i < SHTerms(lmax); ++i)
00297 c_probe[i] = 0.f;
00298 SHProjectIncidentIndirectRadiance(p, 0.f, time, renderer,
00299 origSample, scene, lmax, rng, nIndirSamples, c_probe);
00300 for (int i = 0; i < SHTerms(lmax); ++i)
00301 c_in[i] += c_probe[i];
00302 }
00303 arena.FreeAll();
00304 }
00305
00306 if (nFound > 0)
00307 for (int i = 0; i < SHTerms(lmax); ++i)
00308 c_in[i] /= nFound;
00309 delete[] c_probe;
00310 prog.Update();
00311 }
00312
00313
00314 CreateRadianceProbes *CreateRadianceProbesRenderer(const Camera *camera,
00315 SurfaceIntegrator *surf, VolumeIntegrator *vol,
00316 const ParamSet ¶ms) {
00317 bool includeDirect = params.FindOneBool("directlighting", true);
00318 bool includeIndirect = params.FindOneBool("indirectlighting", true);
00319 int lmax = params.FindOneInt("lmax", 4);
00320 int nindir = params.FindOneInt("indirectsamples", 512);
00321 int nbbox;
00322 BBox bounds;
00323 const float *b = params.FindFloat("bounds", &nbbox);
00324 if (b) {
00325 if (nbbox != 6) Warning("Expecting six values [x0 y0 z0 x1 y1 z1] for bounds");
00326 else bounds = BBox(Point(b[0], b[1], b[2]), Point(b[3], b[4], b[5]));
00327 }
00328 float probeSpacing = params.FindOneFloat("samplespacing", 1.f);
00329 float time = params.FindOneFloat("time", 0.f);
00330 string filename = params.FindOneString("filename", "probes.out");
00331
00332 return new CreateRadianceProbes(surf, vol, camera, lmax, probeSpacing,
00333 bounds, nindir, includeDirect, includeIndirect, time, filename);
00334 }
00335
00336