コード例 #1
0
ファイル: primitive.cpp プロジェクト: papaboo/pbrt-v3
bool GeometricPrimitive::Intersect(const Ray &r, SurfaceInteraction *si) const {
    Float tHit;
    if (!shape->Intersect(r, &tHit, si)) return false;
    r.tMax = tHit;
    si->primitive = this;
    Assert(Dot(si->n, si->shading.n) >= 0.);
    // Initialize _SurfaceInteraction::mediumInterface_ after _Shape_
    // intersection
    if (mediumInterface.IsMediumTransition())
        si->mediumInterface = mediumInterface;
    else
        si->mediumInterface = MediumInterface(r.medium);
    return true;
}
コード例 #2
0
ファイル: infinite.cpp プロジェクト: PINK-FL0YD/pbrt-v3
// InfiniteAreaLight Method Definitions
InfiniteAreaLight::InfiniteAreaLight(const Transform &LightToWorld,
                                     const Spectrum &L, int nSamples,
                                     const std::string &texmap)
    : Light((int)LightFlags::Infinite, LightToWorld, MediumInterface(),
            nSamples) {
    // Read texel data from _texmap_ and initialize _Lmap_
    Point2i resolution;
    std::unique_ptr<RGBSpectrum[]> texels(nullptr);
    if (texmap != "") {
        texels = ReadImage(texmap, &resolution);
        if (texels)
            for (int i = 0; i < resolution.x * resolution.y; ++i)
                texels[i] *= L.ToRGBSpectrum();
    }
    if (!texels) {
        resolution.x = resolution.y = 1;
        texels = std::unique_ptr<RGBSpectrum[]>(new RGBSpectrum[1]);
        texels[0] = L.ToRGBSpectrum();
    }
    Lmap.reset(new MIPMap<RGBSpectrum>(resolution, texels.get()));

    // Initialize sampling PDFs for infinite area light

    // Compute scalar-valued image _img_ from environment map
    int width = 2 * Lmap->Width(), height = 2 * Lmap->Height();
    std::unique_ptr<Float[]> img(new Float[width * height]);
    float fwidth = 0.5f / std::min(width, height);
    ParallelFor(
        [&](int64_t v) {
            Float vp = (v + .5f) / (Float)height;
            Float sinTheta = std::sin(Pi * (v + .5f) / height);
            for (int u = 0; u < width; ++u) {
                Float up = (u + .5f) / (Float)width;
                img[u + v * width] = Lmap->Lookup(Point2f(up, vp), fwidth).y();
                img[u + v * width] *= sinTheta;
            }
        },
        height, 32);

    // Compute sampling distributions for rows and columns of image
    distribution.reset(new Distribution2D(img.get(), width, height));
}
コード例 #3
0
ファイル: lightdistrib.cpp プロジェクト: wjakob/pbrt-v3
const Distribution1D *SpatialLightDistribution::Lookup(const Point3f &p) const {
    ProfilePhase _(Prof::LightDistribLookup);
    ++nLookups;

    // Compute integer voxel coordinates for the given point |p| with
    // respect to the overall voxel grid.
    Vector3f offset = scene.WorldBound().Offset(p);  // offset in [0,1].
    Point3i pi;
    for (int i = 0; i < 3; ++i) pi[i] = int(offset[i] * nVoxels[i]);

    // Create the per-thread cache of sampling distributions if needed.
    LocalBucketHash *localVoxelDistribution =
        localVoxelDistributions[ThreadIndex].get();
    if (!localVoxelDistribution) {
        LOG(INFO) << "Created per-thread SpatialLightDistribution for thread" <<
            ThreadIndex;
        localVoxelDistribution = new LocalBucketHash;
        localVoxelDistributions[ThreadIndex].reset(localVoxelDistribution);
    }
    else {
        // Otherwise see if we have a sampling distribution for the voxel
        // that |p| is in already available in the local cache.
        auto iter = localVoxelDistribution->find(pi);
        if (iter != localVoxelDistribution->end())
            return iter->second;
    }

    // Now we need to either get the distribution from the shared hash
    // table (if another thread has already created it), or create it
    // ourselves and add it to the shared table.
    ProfilePhase __(Prof::LightDistribLookupL2);

    // First, compute a hash into the first-level hash table.
    size_t hash = std::hash<int>{}(pi[0] + nVoxels[0] * pi[1] +
                                   nVoxels[0] * nVoxels[1] * pi[2]);
    hash &= (nBuckets - 1);

    // Acquire the lock for the corresponding second-level hash table.
    std::lock_guard<std::mutex> lock(mutexes[hash]);
    // See if we can find it.
    auto iter = voxelDistribution[hash].find(pi);
    if (iter != voxelDistribution[hash].end()) {
        // Success. Add the pointer to the thread-specific hash table so
        // that we can look up this distribution more efficiently in the
        // future.
        (*localVoxelDistribution)[pi] = iter->second.get();
        return iter->second.get();
    }

    // We need to compute a new sampling distriibution for this voxel. Note
    // that we're holding the lock for the first-level hash table bucket
    // throughout the following; in general, we'd like to do the following
    // quickly so that other threads don't get held up waiting for that
    // lock (for this or other voxels that share it).
    ProfilePhase ___(Prof::LightDistribCreation);
    ++nCreated;
    ++nDistributions;

    // Compute the world-space bounding box of the voxel.
    Point3f p0(Float(pi[0]) / Float(nVoxels[0]),
               Float(pi[1]) / Float(nVoxels[1]),
               Float(pi[2]) / Float(nVoxels[2]));
    Point3f p1(Float(pi[0] + 1) / Float(nVoxels[0]),
               Float(pi[1] + 1) / Float(nVoxels[1]),
               Float(pi[2] + 1) / Float(nVoxels[2]));
    Bounds3f voxelBounds(scene.WorldBound().Lerp(p0),
                         scene.WorldBound().Lerp(p1));

    // Compute the sampling distribution. Sample a number of points inside
    // voxelBounds using a 3D Halton sequence; at each one, sample each
    // light source and compute a weight based on Li/pdf for the light's
    // sample (ignoring visibility between the point in the voxel and the
    // point on the light source) as an approximation to how much the light
    // is likely to contribute to illumination in the voxel.
    int nSamples = 128;
    std::vector<Float> lightContrib(scene.lights.size(), Float(0));
    for (int i = 0; i < nSamples; ++i) {
        Point3f po = voxelBounds.Lerp(Point3f(
            RadicalInverse(0, i), RadicalInverse(1, i), RadicalInverse(2, i)));
        Interaction intr(po, Normal3f(), Vector3f(), Vector3f(1, 0, 0),
                         0 /* time */, MediumInterface());

        // Use the next two Halton dimensions to sample a point on the
        // light source.
        Point2f u(RadicalInverse(3, i), RadicalInverse(4, i));
        for (size_t j = 0; j < scene.lights.size(); ++j) {
            Float pdf;
            Vector3f wi;
            VisibilityTester vis;
            Spectrum Li = scene.lights[j]->Sample_Li(intr, u, &wi, &pdf, &vis);
            if (pdf > 0) {
                // TODO: look at tracing shadow rays / computing beam
                // transmittance.  Probably shouldn't give those full weight
                // but instead e.g. have an occluded shadow ray scale down
                // the contribution by 10 or something.
                lightContrib[j] += Li.y() / pdf;
            }
        }
    }

    // We don't want to leave any lights with a zero probability; it's
    // possible that a light contributes to points in the voxel even though
    // we didn't find such a point when sampling above.  Therefore, compute
    // a minimum (small) weight and ensure that all lights are given at
    // least the corresponding probability.
    Float sumContrib =
        std::accumulate(lightContrib.begin(), lightContrib.end(), Float(0));
    Float avgContrib = sumContrib / (nSamples * lightContrib.size());
    Float minContrib = (avgContrib > 0) ? .001 * avgContrib : 1;
    for (size_t i = 0; i < lightContrib.size(); ++i) {
        VLOG(2) << "Voxel pi = " << pi << ", light " << i << " contrib = "
                << lightContrib[i];
        lightContrib[i] = std::max(lightContrib[i], minContrib);
    }
    LOG(INFO) << "Initialized light distribution in voxel pi= " <<  pi <<
        ", avgContrib = " << avgContrib;

    // Compute a sampling distribution from the accumulated
    // contributions.
    std::unique_ptr<Distribution1D> distrib(
        new Distribution1D(&lightContrib[0], lightContrib.size()));

    // Store a pointer to it in the per-thread cache for the future.
    (*localVoxelDistribution)[pi] = distrib.get();

    // Store the canonical unique_ptr for it in the global hash table so
    // other threads can use it.
    voxelDistribution[hash][pi] = std::move(distrib);

    return (*localVoxelDistribution)[pi];
}
コード例 #4
0
ファイル: lightdistrib.cpp プロジェクト: dbadb/pbrt-v3
Distribution1D *
SpatialLightDistribution::ComputeDistribution(Point3i pi) const {
    ProfilePhase _(Prof::LightDistribCreation);
    ++nCreated;
    ++nDistributions;

    // Compute the world-space bounding box of the voxel corresponding to
    // |pi|.
    Point3f p0(Float(pi[0]) / Float(nVoxels[0]),
               Float(pi[1]) / Float(nVoxels[1]),
               Float(pi[2]) / Float(nVoxels[2]));
    Point3f p1(Float(pi[0] + 1) / Float(nVoxels[0]),
               Float(pi[1] + 1) / Float(nVoxels[1]),
               Float(pi[2] + 1) / Float(nVoxels[2]));
    Bounds3f voxelBounds(scene.WorldBound().Lerp(p0),
                         scene.WorldBound().Lerp(p1));

    // Compute the sampling distribution. Sample a number of points inside
    // voxelBounds using a 3D Halton sequence; at each one, sample each
    // light source and compute a weight based on Li/pdf for the light's
    // sample (ignoring visibility between the point in the voxel and the
    // point on the light source) as an approximation to how much the light
    // is likely to contribute to illumination in the voxel.
    int nSamples = 128;
    std::vector<Float> lightContrib(scene.lights.size(), Float(0));
    for (int i = 0; i < nSamples; ++i) {
        Point3f po = voxelBounds.Lerp(Point3f(
            RadicalInverse(0, i), RadicalInverse(1, i), RadicalInverse(2, i)));
        Interaction intr(po, Normal3f(), Vector3f(), Vector3f(1, 0, 0),
                         0 /* time */, MediumInterface());

        // Use the next two Halton dimensions to sample a point on the
        // light source.
        Point2f u(RadicalInverse(3, i), RadicalInverse(4, i));
        for (size_t j = 0; j < scene.lights.size(); ++j) {
            Float pdf;
            Vector3f wi;
            VisibilityTester vis;
            Spectrum Li = scene.lights[j]->Sample_Li(intr, u, &wi, &pdf, &vis);
            if (pdf > 0) {
                // TODO: look at tracing shadow rays / computing beam
                // transmittance.  Probably shouldn't give those full weight
                // but instead e.g. have an occluded shadow ray scale down
                // the contribution by 10 or something.
                lightContrib[j] += Li.y() / pdf;
            }
        }
    }

    // We don't want to leave any lights with a zero probability; it's
    // possible that a light contributes to points in the voxel even though
    // we didn't find such a point when sampling above.  Therefore, compute
    // a minimum (small) weight and ensure that all lights are given at
    // least the corresponding probability.
    Float sumContrib =
        std::accumulate(lightContrib.begin(), lightContrib.end(), Float(0));
    Float avgContrib = sumContrib / (nSamples * lightContrib.size());
    Float minContrib = (avgContrib > 0) ? .001 * avgContrib : 1;
    for (size_t i = 0; i < lightContrib.size(); ++i) {
        VLOG(2) << "Voxel pi = " << pi << ", light " << i << " contrib = "
                << lightContrib[i];
        lightContrib[i] = std::max(lightContrib[i], minContrib);
    }
    LOG(INFO) << "Initialized light distribution in voxel pi= " <<  pi <<
        ", avgContrib = " << avgContrib;

    // Compute a sampling distribution from the accumulated contributions.
    return new Distribution1D(&lightContrib[0], lightContrib.size());
}