Example #1
0
int main(int argc, char *argv[]) 
{
    pbrtInit();

    // number of monte carlo estimates
    //const int estimates = 1;
    const int estimates = 10000000;

    // radiance of uniform environment map
    const double environmentRadiance = 1.0;


    fprintf(stderr, "outgoing radiance from a surface viewed\n"
        "straight on with uniform lighting\n\n"
        "    uniform incoming radiance = %.3f\n"
        "    monte carlo samples = %d\n\n\n",
        environmentRadiance, estimates);


    CreateBSDFFunc BSDFFuncArray[] = {
//CO        createBlinn0,
//CO        createBlinn05,
//CO        createBlinn2,
//CO        createBlinn30and0,
        createAniso0_0,
        createAniso30_30,
        createLambertian,
        createOrenNayar0,
        createOrenNayar20,
        createFresnelBlend0,
        createFresnelBlend30,
        createPlastic,
        createSubstrate,
    };

    const char* BSDFFuncDescripArray[] = {
//CO        "Blinn (exponent 0)",
//CO        "Blinn (exponent 0.5)",
//CO        "Blinn (exponent 2)",
//CO        "Blinn (exponent 30 and 0)",
        "Anisotropic (exponent 0, 0)",
        "Anisotropic (exponent 30, 30)",
        "Lambertian",
        "Oren Nayar (sigma 0)",
        "Oren Nayar (sigma 20)",
        "FresnelBlend (Blinn exponent 0)",
        "FresnelBlend (Blinn exponent 30)",
        "Plastic",
        "Substrate",
    };

    GenSampleFunc SampleFuncArray[] = {
        Gen_Sample_f,
        Gen_CosHemisphere,
        Gen_UniformHemisphere,
    };

    const char* SampleFuncDescripArray[] = {
        "BSDF Importance Sampling",
        "Cos Hemisphere",
        "Uniform Hemisphere",
    };

    int numModels = sizeof(BSDFFuncArray) / sizeof(BSDFFuncArray[0]);
    int numModelsDescrip = sizeof(BSDFFuncDescripArray) /
        sizeof(BSDFFuncDescripArray[0]);
    int numGenerators = sizeof(SampleFuncArray) / sizeof(SampleFuncArray[0]);
    int numGeneratorsDescrip = sizeof(SampleFuncDescripArray) /
        sizeof(SampleFuncDescripArray[0]);

    if (numModels != numModelsDescrip) {
        fprintf(stderr, "BSDFFuncArray and BSDFFuncDescripArray out of sync!\n");
        exit(1);
    }

    if (numGenerators != numGeneratorsDescrip) {
        fprintf(stderr, "SampleFuncArray and SampleFuncDescripArray out of sync!\n");
        exit(1);
    }

    // for each bsdf model
    for (int model = 0; model < numModels; model++) {

        BSDF* bsdf;

        // create BSDF which requires creating a Shape, casting a Ray
        // that hits the shape to get a DifferentialGeometry object,
        // and passing the DifferentialGeometry object into the BSDF
        {
            Transform t = RotateX(-90);
            bool reverseOrientation = false;
            ParamSet p;

            Reference<Shape> disk = new Disk(new Transform(t), new Transform(Inverse(t)),
                                             reverseOrientation, 0., 1., 0, 360.);
            if (!disk) {
                fprintf(stderr, "Could not load disk plugin\n"
                    "  make sure the PBRT_SEARCHPATH environment variable is set\n");
                exit(1);
            }

            Point origin(0.1, 1, 0);  // offset slightly so we don't hit center of disk
            Vector direction(0, -1, 0);
            float tHit, rayEps;
            Ray r(origin, direction, 1e-3, INFINITY);
            DifferentialGeometry* dg = BSDF_ALLOC(arena, DifferentialGeometry)();
            disk->Intersect(r, &tHit, &rayEps, dg);

            bsdf = BSDF_ALLOC(arena, BSDF)(*dg, dg->nn);
            (BSDFFuncArray[model])(bsdf);
        }


        // facing directly at normal
        Vector woL = Normalize(Vector(0, 0, 1));
        Vector wo = bsdf->LocalToWorld(woL);
        const Normal &n = bsdf->dgShading.nn;

        // for each method of generating samples over the hemisphere
        for (int gen = 0; gen < numGenerators; gen++) {
            double redSum = 0.0;

            const int numHistoBins = 10;
            double histogram[numHistoBins][numHistoBins];
            for (int i = 0; i < numHistoBins; i++) {
                for (int j = 0; j < numHistoBins; j++) {
                    histogram[i][j] = 0;
                }
            }
            int badSamples = 0;
            int outsideSamples = 0;

            int warningTarget = 1;
            for (int sample = 0; sample < estimates; sample++) {
                Vector wi;
                float pdf;
                Spectrum f;

                // sample hemisphere around bsdf, wo is fixed
                (SampleFuncArray[gen])(bsdf, wo, & wi, & pdf, & f);

                double redF = spectrumRedValue(f);

                // add hemisphere sample to histogram
                Vector wiL = bsdf->WorldToLocal(wi);
                float x = Clamp(wiL.x, -1.f, 1.f);
                float y = Clamp(wiL.y, -1.f, 1.f);
                float wiPhi = (atan2(y, x) + M_PI) / (2.0 * M_PI);
                float wiCosTheta = wiL.z;
                bool validSample = (wiCosTheta > 1e-7);
                if (wiPhi < -0.0001 || wiPhi > 1.0001 || wiCosTheta > 1.0001) {
                    // wiCosTheta can be less than 0
                    fprintf(stderr, "bad wi! %.3f %.3f %.3f, (%.3f %.3f)\n",
                        wiL[0], wiL[1], wiL[2], wiPhi, wiCosTheta);
                } else if (validSample) {
                    int histoPhi      = (int) (wiPhi * numHistoBins);
                    int histoCosTheta = (int) (wiCosTheta * numHistoBins);
                    histogram[histoCosTheta][histoPhi] += 1.0 / pdf;
                }

                if (!validSample) {
                    outsideSamples++;
                } else if (pdf == 0.f || isnan(pdf) || redF < 0 || isnan(redF)) {
                    if (badSamples == warningTarget) {
                        fprintf(stderr, "warning %d, bad sample %d! "
                            "pdf: %.3f, redF: %.3f\n",
                            warningTarget, sample, pdf, redF);
                        warningTarget *= 10;
                    }
                    badSamples++;
                } else {
                    // outgoing radiance estimate =
                    //   bsdf * incomingRadiance * cos(wi) / pdf
                    redSum += redF * environmentRadiance * AbsDot(wi, n) / pdf;
                }
            }
            int goodSamples = estimates - badSamples;

            // print results
            fprintf(stderr, "*** BRDF: '%s', Samples: '%s'\n\n"
                "wi histogram showing the relative weight in each bin\n"
                "  all entries should be close to 2pi = %.5f:\n"
                "  (%d bad samples, %d outside samples)\n\n"
                "                          cos(theta) bins\n",
                BSDFFuncDescripArray[model], SampleFuncDescripArray[gen],
                M_PI * 2.0, badSamples, outsideSamples);
            double totalSum = 0.0;
            for (int i = 0; i < numHistoBins; i++) {
                fprintf(stderr, "  phi bin %02d:", i);
                for (int j = 0; j < numHistoBins; j++) {
                    fprintf(stderr, " %5.2f", histogram[i][j] *
                        numHistoBins * numHistoBins / goodSamples);
                    totalSum += histogram[i][j];
                }
                fprintf(stderr, "\n");
            }
            fprintf(stderr, "\n  final average :  %.5f (error %.5f)\n\n"
                "  radiance = %.5f\n\n",
                totalSum / goodSamples, totalSum / goodSamples - M_PI * 2.0,
                redSum / goodSamples);
        }
    }
    
    pbrtCleanup();
    return 0;
}