Spectrum GonioPhotometricLight::Sample_L(const Scene *scene, float u1, float u2, float u3, float u4, Ray *ray, float *pdf) const { ray->o = lightPos; ray->d = UniformSampleSphere(u1, u2); *pdf = UniformSpherePdf(); return Intensity * Scale(ray->d); }
Spectrum GonioPhotometricLight::Sample_L(const Scene *scene, const LightSample &ls, float u1, float u2, float time, Ray *ray, Normal *Ns, float *pdf) const { *ray = Ray(lightPos, UniformSampleSphere(ls.uPos[0], ls.uPos[1]), 0.f, INFINITY, time); *Ns = (Normal)ray->d; *pdf = UniformSpherePdf(); return Intensity * Scale(ray->d); }
Point Sphere::Sample(Float u1, Float u2, Normal *Ns) const { Point p = Point(0, 0, 0) + mRad * UniformSampleSphere(u1, u2); *Ns = Normalize((*localToWorld)(Normal(p.x, p.y, p.z))); //TODO 这样转换法线正确吗? if (ReverseOrientation) *Ns *= -1.f; return (*localToWorld)(p); }
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(); }
Spectrum GonioPhotometricLight::Sample_L(const Scene *scene, const LightSample &ls, float u1, float u2, Ray *ray, Normal *Ns, float *pdf) const { ray->o = lightPos; ray->d = UniformSampleSphere(ls.uPos[0], ls.uPos[1]); *Ns = (Normal)ray->d; *pdf = UniformSpherePdf(); return Intensity * Scale(ray->d); }
bool Sphere::Sample(const Point2f &sample, Interaction *it) const { Point3f pObj = Point3f(0, 0, 0) + radius * UniformSampleSphere(sample); it->n = Normalize((*ObjectToWorld)(Normal3f(pObj.x, pObj.y, pObj.z))); if (ReverseOrientation) it->n *= -1.f; Vector3f pObjError = 16.f * MachineEpsilon * Vector3f(radius, radius, radius); it->p = (*ObjectToWorld)(pObj, pObjError, &it->pError); return true; }
Spectrum GonioPhotometricLight::Sample_L(const Point2f &sample1, const Point2f &sample2, Float time, Ray *ray, Normal3f *Ns, Float *pdfPos, Float *pdfDir) const { *ray = Ray(pLight, UniformSampleSphere(sample1), Infinity, time, 0, medium); *Ns = (Normal3f)ray->d; *pdfPos = 1.f; *pdfDir = UniformSpherePdf(); return intensity * Scale(ray->d); }
Spectrum PointLight::Sample_Le(const Point2f &u1, const Point2f &u2, Float time, Ray *ray, Normal3f *nLight, Float *pdfPos, Float *pdfDir) const { *ray = Ray(pLight, UniformSampleSphere(u1), Infinity, time, mediumInterface.inside); *nLight = (Normal3f)ray->d; *pdfPos = 1; *pdfDir = UniformSpherePdf(); return I; }
Spectrum AreaLight::Sample_L(const Scene *scene, float u1, float u2, float u3, float u4, Ray *ray, float *pdf) const { Normal ns; ray->o = shape->Sample(u1, u2, &ns); ray->d = UniformSampleSphere(u3, u4); if (Dot(ray->d, ns) < 0.) ray->d *= -1; *pdf = shape->Pdf(ray->o) * INV_TWOPI; return L(ray->o, ns, ray->d); }
Interaction Sphere::Sample(const Point2f &u) const { Interaction it; Point3f pObj = Point3f(0, 0, 0) + radius * UniformSampleSphere(u); it.n = Normalize((*ObjectToWorld)(Normal3f(pObj.x, pObj.y, pObj.z))); if (reverseOrientation) it.n *= -1.f; // Reproject _pObj_ to sphere surface and compute _pObjError_ pObj *= radius / Distance(pObj, Point3f(0, 0, 0)); Vector3f pObjError = gamma(5) * Abs((Vector3f)pObj); it.p = (*ObjectToWorld)(pObj, pObjError, &it.pError); return it; }
Spectrum GonioPhotometricLight::Sample_Le(const Point2f &u1, const Point2f &u2, Float time, Ray *ray, Normal3f *nLight, Float *pdfPos, Float *pdfDir) const { *ray = Ray(pLight, UniformSampleSphere(u1), Infinity, time, 0, mediumInterface.inside); *nLight = (Normal3f)ray->d; *pdfPos = 1.f; *pdfDir = UniformSpherePdf(); return intensity * Scale(ray->d); }
Spectrum InfiniteAreaLightIS::Sample_L(const Scene *scene, float u1, float u2, float u3, float u4, Ray *ray, float *pdf) const { // Choose two points _p1_ and _p2_ on scene bounding sphere Point worldCenter; float worldRadius; scene->WorldBound().BoundingSphere(&worldCenter, &worldRadius); worldRadius *= 1.01f; Point p1 = worldCenter + worldRadius * UniformSampleSphere(u1, u2); Point p2 = worldCenter + worldRadius * UniformSampleSphere(u3, u4); // Construct ray between _p1_ and _p2_ ray->o = p1; ray->d = Normalize(p2-p1); // Compute _InfiniteAreaLightIS_ ray weight Vector to_center = Normalize(worldCenter - p1); float costheta = AbsDot(to_center,ray->d); *pdf = costheta / ((4.f * M_PI * worldRadius * worldRadius)); return Le(RayDifferential(ray->o, -ray->d)); }
// AmbientOcclusionIntegrator Method Definitions Spectrum AmbientOcclusionIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Intersection &isect, const Sample *sample, RNG &rng, MemoryArena &arena, int wavelength) const { BSDF *bsdf = isect.GetBSDF(ray, arena, wavelength); const Point &p = bsdf->dgShading.p; Normal n = Faceforward(isect.dg.nn, -ray.d); uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; float u[2]; int nClear = 0; for (int i = 0; i < nSamples; ++i) { Sample02(i, scramble, u); Vector w = UniformSampleSphere(u[0], u[1]); if (Dot(w, n) < 0.) w = -w; Ray r(p, w, .01f, maxDist); if (!scene->IntersectP(r)) ++nClear; } return Spectrum(float(nClear) / float(nSamples)); }
// sample a ray from light Spectrum PointLight::sample_l( const LightSample& ls , Ray& r , float* pdfW , float* pdfA , float* cosAtLight ) const { // sample a new ray r.m_fMin = 0.0f; r.m_fMax = FLT_MAX; r.m_Ori = light_pos; r.m_Dir = UniformSampleSphere( ls.u , ls.v ); // product of pdf of sampling a point w.r.t surface area and a direction w.r.t direction if( pdfW ) *pdfW = UniformSpherePdf(); // pdf w.r.t surface area if( pdfA ) *pdfA = 1.0f; if( cosAtLight ) *cosAtLight = 1.0f; return intensity; }
Point Sphere::Sample(float u1, float u2, Normal *ns) const { Point p = Point(0,0,0) + radius * UniformSampleSphere(u1, u2); *ns = Normalize((*ObjectToWorld)(Normal(p.x, p.y, p.z))); if (ReverseOrientation) *ns *= -1.f; return (*ObjectToWorld)(p); }
void SurfacePointTask::Run() { // Declare common variables for _SurfacePointTask::Run()_ RNG rng(37 * taskNum); MemoryArena arena; vector<SurfacePoint> candidates; while (true) { int pathsTraced, raysTraced = 0; for (pathsTraced = 0; pathsTraced < 20000; ++pathsTraced) { // Follow ray path and attempt to deposit candidate sample points Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); Ray ray(origin, dir, 0.f, INFINITY, time); while (ray.depth < 30) { // Find ray intersection with scene geometry or bounding sphere ++raysTraced; bool hitOnSphere = false; auto optIsect = scene.Intersect(ray); if (!optIsect) { optIsect = sphere.Intersect(ray); if (!optIsect) break; hitOnSphere = true; } DifferentialGeometry &hitGeometry = optIsect->dg; hitGeometry.nn = Faceforward(hitGeometry.nn, -ray.d); // Store candidate sample point at ray intersection if appropriate if (!hitOnSphere && ray.depth >= 3 && optIsect->GetBSSRDF(RayDifferential(ray), arena) != NULL) { float area = M_PI * (minSampleDist / 2.f) * (minSampleDist / 2.f); candidates.push_back(SurfacePoint(hitGeometry.p, hitGeometry.nn, area, optIsect->rayEpsilon)); } // Generate random ray from intersection point Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); dir = Faceforward(dir, hitGeometry.nn); ray = Ray(hitGeometry.p, dir, ray, optIsect->rayEpsilon); } arena.FreeAll(); } // Make first pass through candidate points with reader lock vector<bool> candidateRejected; candidateRejected.reserve(candidates.size()); RWMutexLock lock(mutex, READ); for (uint32_t i = 0; i < candidates.size(); ++i) { PoissonCheck check(minSampleDist, candidates[i].p); octree.Lookup(candidates[i].p, check); candidateRejected.push_back(check.failed); } // Make second pass through points with writer lock and update octree lock.UpgradeToWrite(); if (repeatedFails >= maxFails) return; totalPathsTraced += pathsTraced; totalRaysTraced += raysTraced; int oldMaxRepeatedFails = maxRepeatedFails; for (uint32_t i = 0; i < candidates.size(); ++i) { if (candidateRejected[i]) { // Update for rejected candidate point ++repeatedFails; maxRepeatedFails = max(maxRepeatedFails, repeatedFails); if (repeatedFails >= maxFails) return; } else { // Recheck candidate point and possibly add to octree SurfacePoint &sp = candidates[i]; PoissonCheck check(minSampleDist, sp.p); octree.Lookup(sp.p, check); if (check.failed) { // Update for rejected candidate point ++repeatedFails; maxRepeatedFails = max(maxRepeatedFails, repeatedFails); if (repeatedFails >= maxFails) return; } else { ++numPointsAdded; repeatedFails = 0; Vector delta(minSampleDist, minSampleDist, minSampleDist); octree.Add(sp, BBox(sp.p-delta, sp.p+delta)); PBRT_SUBSURFACE_ADDED_POINT_TO_OCTREE(&sp, minSampleDist); surfacePoints.push_back(sp); } } } // Stop following paths if not finding new points if (repeatedFails > oldMaxRepeatedFails) { int delta = repeatedFails - oldMaxRepeatedFails; prog.Update(delta); } if (totalPathsTraced > 50000 && numPointsAdded == 0) { Warning("There don't seem to be any objects with BSSRDFs " "in this scene. Giving up."); return; } candidates.erase(candidates.begin(), candidates.end()); } }
void CreateRadianceProbes::Render(const Scene *scene) { // Compute scene bounds and initialize probe integrators if (bbox.pMin.x > bbox.pMax.x) bbox = scene->WorldBound(); surfaceIntegrator->Preprocess(scene, camera, this); volumeIntegrator->Preprocess(scene, camera, this); Sample *origSample = new Sample(NULL, surfaceIntegrator, volumeIntegrator, scene); // Compute sampling rate in each dimension Vector delta = bbox.pMax - bbox.pMin; int nProbes[3]; for (int i = 0; i < 3; ++i) nProbes[i] = max(1, Ceil2Int(delta[i] / probeSpacing)); // Allocate SH coefficient vector pointers for sample points int count = nProbes[0] * nProbes[1] * nProbes[2]; Spectrum **c_in = new Spectrum *[count]; for (int i = 0; i < count; ++i) c_in[i] = new Spectrum[SHTerms(lmax)]; // Compute random points on surfaces of scene // 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); GeometricPrimitive sphere(sph, nullMaterial, NULL); vector<Point> surfacePoints; uint32_t nPoints = 32768, maxDepth = 32; surfacePoints.reserve(nPoints + maxDepth); Point pCamera = camera->CameraToWorld(camera->shutterOpen, Point(0, 0, 0)); surfacePoints.push_back(pCamera); RNG rng; while (surfacePoints.size() < nPoints) { // Generate random path from camera and deposit surface points Point pray = pCamera; Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); float rayEpsilon = 0.f; for (uint32_t i = 0; i < maxDepth; ++i) { Ray ray(pray, dir, rayEpsilon, INFINITY, time); Intersection isect; if (!scene->Intersect(ray, &isect) && !sphere.Intersect(ray, &isect)) break; surfacePoints.push_back(ray(ray.maxt)); DifferentialGeometry &hitGeometry = isect.dg; pray = isect.dg.p; rayEpsilon = isect.rayEpsilon; hitGeometry.nn = Faceforward(hitGeometry.nn, -ray.d); dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); dir = Faceforward(dir, hitGeometry.nn); } } // Launch tasks to compute radiance probes at sample points vector<Task *> tasks; ProgressReporter prog(count, "Radiance Probes"); for (int i = 0; i < count; ++i) tasks.push_back(new CreateRadProbeTask(i, nProbes, time, bbox, lmax, includeDirectInProbes, includeIndirectInProbes, nIndirSamples, prog, origSample, surfacePoints, scene, this, c_in[i])); EnqueueTasks(tasks); WaitForAllTasks(); for (uint32_t i = 0; i < tasks.size(); ++i) delete tasks[i]; prog.Done(); // Write radiance probe coefficients to file FILE *f = fopen(filename.c_str(), "w"); if (f) { if (fprintf(f, "%d %d %d\n", lmax, includeDirectInProbes?1:0, includeIndirectInProbes?1:0) < 0 || fprintf(f, "%d %d %d\n", nProbes[0], nProbes[1], nProbes[2]) < 0 || fprintf(f, "%f %f %f %f %f %f\n", bbox.pMin.x, bbox.pMin.y, bbox.pMin.z, bbox.pMax.x, bbox.pMax.y, bbox.pMax.z) < 0) { Error("Error writing radiance file \"%s\" (%s)", filename.c_str(), strerror(errno)); exit(1); } for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) { for (int j = 0; j < SHTerms(lmax); ++j) { fprintf(f, " "); if (c_in[i][j].Write(f) == false) { Error("Error writing radiance file \"%s\" (%s)", filename.c_str(), strerror(errno)); exit(1); } fprintf(f, "\n"); } fprintf(f, "\n"); } fclose(f); } for (int i = 0; i < nProbes[0] * nProbes[1] * nProbes[2]; ++i) delete[] c_in[i]; delete[] c_in; delete origSample; }