예제 #1
0
파일: bsdfs.cpp 프로젝트: Drooids/pbrt-v3
/// Generate a histogram of the BSDF density function via MC sampling
void FrequencyTable(const BSDF* bsdf, const Vector3f& wo, RNG& rng,
                    int sampleCount, int thetaRes, int phiRes, Float* target) {
    memset(target, 0, thetaRes * phiRes * sizeof(Float));

    Float factorTheta = thetaRes / Pi, factorPhi = phiRes / (2 * Pi);

    BxDFType flags;
    Vector3f wi;
    Float pdf;

    for (int i = 0; i < sampleCount; ++i) {
        Point2f sample {rng.UniformFloat(), rng.UniformFloat()};
        Spectrum f = bsdf->Sample_f(wo, &wi, sample, &pdf, BSDF_ALL, &flags);

        if (f == Spectrum() || (flags & BSDF_SPECULAR)) continue;

        Vector3f wiL = bsdf->WorldToLocal(wi);

        Point2f coords(std::acos(Clamp(wiL.z, -1, 1)) * factorTheta,
                       std::atan2(wiL.y, wiL.x) * factorPhi);

        if (coords.y < 0) coords.y += 2 * Pi * factorPhi;

        int thetaBin =
            std::min(std::max(0, (int)std::floor(coords.x)), thetaRes - 1);
        int phiBin =
            std::min(std::max(0, (int)std::floor(coords.y)), phiRes - 1);

        target[thetaBin * phiRes + phiBin] += 1;
    }
}
예제 #2
0
void Gen_Sample_f(BSDF* bsdf, const Vector3f& wo, Vector3f* wi, Float* pdf,
                  Spectrum* f) {
    // only glossy or diffuse reflections (no specular reflections)
    BxDFType inflags = BxDFType(BSDF_REFLECTION | BSDF_DIFFUSE | BSDF_GLOSSY);
    BxDFType outflags;
    Point2f sample(rng.UniformFloat(), rng.UniformFloat());
    *f = bsdf->Sample_f(wo, wi, sample, pdf, inflags, &outflags);

    // double check bsdf->Pdf() gives us the same answer
    Vector3f wiL = bsdf->WorldToLocal(*wi);
    float wiCosTheta = wiL.z;
    bool validSample = (wiCosTheta > 1e-7);

    if (validSample) {
        float verifyPdf = bsdf->Pdf(wo, *wi, inflags);
        float relErr = fabs(verifyPdf - *pdf) / *pdf;
        if (relErr > 1e-3) {
            fprintf(stderr,
                    "BSDF::Pdf() doesn't match BSDF::Sample_f() !\n"
                    "  Sample_f pdf %.3f, Pdf pdf %.3f (rel error %f)\n"
                    "  wo %.3f %.3f %.3f, wi %.3f %.3f %.3f\n",
                    *pdf, verifyPdf, relErr, wo[0], wo[1], wo[2], (*wi)[0],
                    (*wi)[1], (*wi)[2]);
            fprintf(
                stderr,
                "blah! validSample %d, wiCosTheta %.3f, wiL %.3f %.3f %.3f\n",
                validSample, wiCosTheta, wiL[0], wiL[1], wiL[2]);
        }
    }
}
예제 #3
0
TEST(EXR, Randoms) {
   int width = 1024;
   int height = 1024;

   RNG rng;
   float *buf = new float[4 * width * height];
   for (int i = 0; i < 4 * width * height; ++i) {
     buf[i] = -20 + 20. * rng.UniformFloat();
   }

   EXRImage image;
   image.num_channels = 4;
   const char *channels[] = { "B", "G", "R", "A" };
   image.channel_names = channels;
   unsigned char *images[] = { (unsigned char *)buf,
                               (unsigned char *)(buf + width * height),
                               (unsigned char *)(buf + 2 * width * height),
                               (unsigned char *)(buf + 3 * width * height) };
   image.images = images;
   int pixel_types[] = { TINYEXR_PIXELTYPE_HALF, TINYEXR_PIXELTYPE_HALF,
                         TINYEXR_PIXELTYPE_HALF, TINYEXR_PIXELTYPE_HALF };
   image.pixel_types = pixel_types;
   image.width = width;
   image.height = height;

   const char *err = nullptr;
   EXPECT_EQ(0, SaveMultiChannelEXRToFile(&image, "test.exr", &err)) << err;

   EXRImage readImage;
   EXPECT_EQ(0, LoadMultiChannelEXRFromFile(&readImage, "test.exr", &err))
       << err;

   CompareImages(image, readImage, true);
}
예제 #4
0
// Sampling Function Definitions
void StratifiedSample1D(Float *samp, int nSamples, RNG &rng, bool jitter) {
    Float invNSamples = (Float)1 / nSamples;
    for (int i = 0; i < nSamples; ++i) {
        Float delta = jitter ? rng.UniformFloat() : 0.5f;
        samp[i] = std::min((i + delta) * invNSamples, OneMinusEpsilon);
    }
}
예제 #5
0
Point2f RejectionSampleDisk(RNG &rng) {
    Point2f p;
    do {
        p.x = 1 - 2 * rng.UniformFloat();
        p.y = 1 - 2 * rng.UniformFloat();
    } while (p.x * p.x + p.y * p.y > 1);
    return p;
}
예제 #6
0
void RealisticCamera::TestExitPupilBounds() const {
    Float filmDiagonal = film->diagonal;

    static RNG rng;

    Float u = rng.UniformFloat();
    Point3f pFilm(u * filmDiagonal / 2, 0, 0);

    Float r = pFilm.x / (filmDiagonal / 2);
    int pupilIndex =
        std::min((int)exitPupilBounds.size() - 1,
                 (int)std::floor(r * (exitPupilBounds.size() - 1)));
    Bounds2f pupilBounds = exitPupilBounds[pupilIndex];
    if (pupilIndex + 1 < (int)exitPupilBounds.size())
        pupilBounds = Union(pupilBounds, exitPupilBounds[pupilIndex + 1]);

    // Now, randomly pick points on the aperture and see if any are outside
    // of pupil bounds...
    for (int i = 0; i < 1000; ++i) {
        Point2f pd = ConcentricSampleDisk(
                         Point2f(rng.UniformFloat(), rng.UniformFloat()));
        pd *= RearElementRadius();

        Ray testRay(pFilm, Point3f(pd.x, pd.y, 0.f) - pFilm);
        Ray testOut;
        if (!TraceLensesFromFilm(testRay, &testOut)) continue;

        if (!Inside(pd, pupilBounds)) {
            fprintf(stderr,
                    "Aha! (%f,%f) went through, but outside bounds (%f,%f) - "
                    "(%f,%f)\n",
                    pd.x, pd.y, pupilBounds.pMin[0], pupilBounds.pMin[1],
                    pupilBounds.pMax[0], pupilBounds.pMax[1]);
            RenderExitPupil(
                (Float)pupilIndex / exitPupilBounds.size() * filmDiagonal / 2.f,
                0.f, "low.exr");
            RenderExitPupil((Float)(pupilIndex + 1) / exitPupilBounds.size() *
                            filmDiagonal / 2.f,
                            0.f, "high.exr");
            RenderExitPupil(pFilm.x, 0.f, "mid.exr");
            exit(0);
        }
    }
    fprintf(stderr, ".");
}
예제 #7
0
void Gen_UniformHemisphere(BSDF* bsdf, const Vector3f& wo, Vector3f* wi,
                           Float* pdf, Spectrum* f) {
    float u1 = rng.UniformFloat();
    float u2 = rng.UniformFloat();
    Vector3f wiL = UniformSampleHemisphere(Point2f(u1, u2));
    *wi = bsdf->LocalToWorld(wiL);
    *pdf = UniformHemispherePdf();

    *f = bsdf->f(wo, *wi);
}
예제 #8
0
void StratifiedSample2D(Point2f *samp, int nx, int ny, RNG &rng, bool jitter) {
    Float dx = (Float)1 / nx, dy = (Float)1 / ny;
    for (int y = 0; y < ny; ++y)
        for (int x = 0; x < nx; ++x) {
            Float jx = jitter ? rng.UniformFloat() : 0.5f;
            Float jy = jitter ? rng.UniformFloat() : 0.5f;
            samp->x = std::min((x + jx) * dx, OneMinusEpsilon);
            samp->y = std::min((y + jy) * dy, OneMinusEpsilon);
            ++samp;
        }
}
예제 #9
0
void Gen_CosHemisphere(BSDF* bsdf, const Vector3f& wo, Vector3f* wi, Float* pdf,
                       Spectrum* f) {
    float u1 = rng.UniformFloat();
    float u2 = rng.UniformFloat();
    Vector3f wiL = CosineSampleHemisphere(Point2f(u1, u2));
    *wi = bsdf->LocalToWorld(wiL);
    float cosTheta = wiL.z;
    *pdf = CosineHemispherePdf(cosTheta);

    *f = bsdf->f(wo, *wi);
}
예제 #10
0
void LatinHypercube(Float *samples, int nSamples, int nDim, RNG &rng) {
    // Generate LHS samples along diagonal
    Float invNSamples = (Float)1 / nSamples;
    for (int i = 0; i < nSamples; ++i)
        for (int j = 0; j < nDim; ++j) {
            Float sj = (i + (rng.UniformFloat())) * invNSamples;
            samples[nDim * i + j] = std::min(sj, OneMinusEpsilon);
        }

    // Permute LHS samples in each dimension
    for (int i = 0; i < nDim; ++i) {
        for (int j = 0; j < nSamples; ++j) {
            int other = j + rng.UniformUInt32(nSamples - j);
            std::swap(samples[nDim * j + i], samples[nDim * other + i]);
        }
    }
}
예제 #11
0
파일: bsdfs.cpp 프로젝트: Drooids/pbrt-v3
void TestBSDF(void (*createBSDF)(BSDF*, MemoryArena&),
              const char* description) {
    MemoryArena arena;

    Options opt;
    pbrtInit(opt);

    const int thetaRes = CHI2_THETA_RES;
    const int phiRes = CHI2_PHI_RES;
    const int sampleCount = CHI2_SAMPLECOUNT;
    Float* frequencies = new Float[thetaRes * phiRes];
    Float* expFrequencies = new Float[thetaRes * phiRes];
    RNG rng;

    int index = 0;
    std::cout.precision(3);

    // Create BSDF, which requires creating a Shape, casting a Ray that
    // hits the shape to get a SurfaceInteraction object.
    BSDF* bsdf = nullptr;
    Transform t = RotateX(-90);
    Transform tInv = Inverse(t);
    {
        bool reverseOrientation = false;
        ParamSet p;

        std::shared_ptr<Shape> disk(
            new Disk(&t, &tInv, reverseOrientation, 0., 1., 0, 360.));
        Point3f origin(0.1, 1,
                       0);  // offset slightly so we don't hit center of disk
        Vector3f direction(0, -1, 0);
        Float tHit;
        Ray r(origin, direction);
        SurfaceInteraction isect;
        disk->Intersect(r, &tHit, &isect);
        bsdf = ARENA_ALLOC(arena, BSDF)(isect);
        createBSDF(bsdf, arena);
    }

    for (int k = 0; k < CHI2_RUNS; ++k) {
        /* Randomly pick an outgoing direction on the hemisphere */
        Point2f sample {rng.UniformFloat(), rng.UniformFloat()};
        Vector3f woL = CosineSampleHemisphere(sample);
        Vector3f wo = bsdf->LocalToWorld(woL);

        FrequencyTable(bsdf, wo, rng, sampleCount, thetaRes, phiRes,
                       frequencies);

        IntegrateFrequencyTable(bsdf, wo, sampleCount, thetaRes, phiRes,
                                expFrequencies);

        std::string filename = StringPrintf("/tmp/chi2test_%s_%03i.m",
                                            description, ++index);
        DumpTables(frequencies, expFrequencies, thetaRes, phiRes,
                   filename.c_str());

        auto result =
            Chi2Test(frequencies, expFrequencies, thetaRes, phiRes, sampleCount,
                     CHI2_MINFREQ, CHI2_SLEVEL, CHI2_RUNS);
        EXPECT_TRUE(result.first) << result.second << ", iteration " << k;
    }

    delete[] frequencies;
    delete[] expFrequencies;

    pbrtCleanup();
}