Пример #1
0
    void weak_white_furnace_test(
        size_t                      num_runs,
        const float                 alpha_x,
        const float                 alpha_y,
        const float                 gamma,
        const float                 angle_step,
        WeakWhiteFurnaceTestResult& result)
    {
        result.m_min_G1 =  numeric_limits<float>::max();
        result.m_max_G1 = -numeric_limits<float>::max();
        result.m_min_result =  numeric_limits<float>::max();
        result.m_max_result = -numeric_limits<float>::max();

        MDF mdf;

        for (size_t i = 0; i < num_runs; ++i)
        {
            static const size_t Bases[] = { 2 };
            const Vector2f s = hammersley_sequence<float, 2>(Bases, num_runs, i);
            const Vector3f v = sample_hemisphere_uniform(s);
            const float G1 = mdf.G1(v, Vector3f(0.0f, 1.0, 0.0f), alpha_x, alpha_y, gamma);

            result.m_min_G1 = std::min(result.m_min_G1, G1);
            result.m_max_G1 = std::max(result.m_max_G1, G1);

            const float cos_thetha_o_4 = std::abs(4.0f * v.y);

            float integral = 0.0f;

            for (float theta = 0.0f; theta < Pi<float>(); theta += angle_step)
            {
                const float cos_theta = std::cos(theta);
                const float sin_theta = std::sin(theta);

                for (float phi = 0.0f; phi < TwoPi<float>(); phi += angle_step)
                {
                    const float cos_phi = std::cos(phi);
                    const float sin_phi = std::sin(phi);

                    const Vector3f l =
                        Vector3f::make_unit_vector(
                            cos_theta,
                            sin_theta,
                            cos_phi,
                            sin_phi);

                    const Vector3f h = normalize(v + l);

                    if (h.y > 0.0f)
                        integral += sin_theta * mdf.D(h, alpha_x, alpha_y, gamma) * G1 / cos_thetha_o_4;
                }
            }

            // Result should be 1.
            integral *= square(angle_step);

            result.m_min_result = std::min(result.m_min_result, integral);
            result.m_max_result = std::max(result.m_max_result, integral);
        }
    }
Пример #2
0
    void weak_white_furnace_test(
        size_t                          num_runs,
        const double                    alpha_x,
        const double                    alpha_y,
        const double                    angle_step,
        WeakWhiteFurnaceTestResult& result)
    {
        result.m_min_G1 =  numeric_limits<double>::max();
        result.m_max_G1 = -numeric_limits<double>::max();
        result.m_min_result =  numeric_limits<double>::max();
        result.m_max_result = -numeric_limits<double>::max();

        MDF mdf;

        for (size_t i = 0; i < num_runs; ++i)
        {
            static const size_t Bases[] = { 2 };
            const Vector2d s = hammersley_sequence<double, 2>(Bases, num_runs, i);
            const Vector3d v = sample_hemisphere_uniform(s);
            const double G1 = mdf.G1(v, Vector3d(0.0, 1.0, 0.0), alpha_x, alpha_y);

            result.m_min_G1 = std::min(result.m_min_G1, G1);
            result.m_max_G1 = std::max(result.m_max_G1, G1);

            const double cos_thetha_o_4 = std::abs(4.0 * v.y);

            double integral = 0.0;

            for (double theta = 0.0; theta < Pi<double>(); theta += angle_step)
            {
                const double cos_theta = std::cos(theta);
                const double sin_theta = std::sin(theta);

                for (double phi = 0.0; phi < TwoPi<double>(); phi += angle_step)
                {
                    const double cos_phi = std::cos(phi);
                    const double sin_phi = std::sin(phi);

                    const Vector3d l =
                        Vector3d::make_unit_vector(
                            cos_theta,
                            sin_theta,
                            cos_phi,
                            sin_phi);

                    const Vector3d h = normalize(v + l);

                    if (h.y > 0.0)
                        integral += sin_theta * mdf.D(h, alpha_x, alpha_y) * G1 / cos_thetha_o_4;
                }
            }

            // Result should be 1.
            integral *= square(angle_step);

            result.m_min_result = std::min(result.m_min_result, integral);
            result.m_max_result = std::max(result.m_max_result, integral);
        }
    }
Пример #3
0
        static void compute_specular_albedo(
            const MDF&          mdf,
            const Spectrum&     rs,
            const Vector3d&     V,
            Spectrum&           albedo)
        {
            // V must lie above or in the surface.
            assert(V.y >= 0.0);

            albedo.set(0.0f);

            for (size_t i = 0; i < AlbedoSampleCount; ++i)
            {
                // Generate a uniform sample in [0,1)^2.
                static const size_t Bases[] = { 2 };
                const Vector2d s = hammersley_sequence<double, 2>(Bases, i, AlbedoSampleCount);

                // Sample the microfacet distribution to get an halfway vector H.
                const Vector3d H = mdf.sample(s);
                const double dot_HV = dot(H, V);
                if (dot_HV <= 0.0)
                    continue;

                // L is the reflection of V around H.
                const Vector3d L = (dot_HV + dot_HV) * H - V;

                // Reject L if it lies in or below the surface.
                if (L.y <= 0.0)
                    continue;

                // Evaluate the PDF of L.
                const double dot_HN = H.y;
                const double pdf_H = mdf.evaluate_pdf(dot_HN);
                const double pdf_L = pdf_H / (4.0 * dot_HV);
                assert(pdf_L >= 0.0);
                if (pdf_L == 0.0)
                    continue;

                // Sanity checks.
                assert(is_normalized(V));
                assert(is_normalized(H));
                assert(is_normalized(L));

                // Evaluate the specular component for this (L, V) pair.
                Spectrum fr_spec;
                fr_spec = fresnel_dielectric_schlick(rs, dot_HV);
                fr_spec *= static_cast<float>((L.y * mdf.evaluate(dot_HN)) / (4.0 * pdf_L * dot_HV * dot_HV));
                albedo += fr_spec;
            }

            albedo /= static_cast<float>(AlbedoSampleCount);
        }
Пример #4
0
    void plot(
        MapleFile&      file,
        const string&   name,
        const MDF&      mdf,
        const size_t    point_count,
        const size_t    sample_count)
    {
        vector<double> angles(point_count);
        vector<double> densities(point_count);

        for (size_t i = 0; i < point_count; ++i)
        {
            const double angle =
                fit(
                    static_cast<double>(i), 0.0, static_cast<double>(point_count - 1),
                    -HalfPi, +HalfPi);
            const double cos_angle = cos(angle);

            angles[i] = rad_to_deg(angle);
            densities[i] = mdf.evaluate(cos_angle) * cos_angle;
        }

        vector<double> angle_samples(sample_count);
        vector<double> density_samples(sample_count);

        for (size_t i = 0; i < sample_count; ++i)
        {
            static const size_t Bases[] = { 2 };
            const Vector2d s = hammersley_sequence<double, 2>(Bases, i, sample_count);
            const Vector3d w = mdf.sample(s);
            const double cos_angle = w.y;
            const double angle = acos(cos_angle) * (w.x < 0.0 ? -1.0 : 1.0);

            angle_samples[i] = rad_to_deg(angle);
            density_samples[i] = mdf.evaluate(cos_angle) * cos_angle;
        }

        file.define(name, angles, densities);
        file.define(name + "_samples", angle_samples, density_samples);

        file.plot(
            make_vector(
                MaplePlotDef(name)
                    .set_legend("Microfacet Distribution Function (" + name + ")"),
                MaplePlotDef(name + "_samples")
                    .set_legend("Integration Samples")
                    .set_style("point")
                    .set_color("red")));
    }
Пример #5
0
    double integrate_sampling(
        const MDF&      mdf,
        const Sampler&  sampler,
        const size_t    sample_count)
    {
        double integral = 0.0;

        for (size_t i = 0; i < sample_count; ++i)
        {
            static const size_t Bases[] = { 2 };
            const Vector2d s = hammersley_sequence<double, 2>(Bases, i, sample_count);

            const Vector3d w = sampler.sample(s);
            const double pdf = sampler.pdf(w);
            const double cos_theta = w.y;

            const double value = mdf.evaluate(cos_theta);
            const double sample = value / pdf;

            integral += sample * cos_theta;
        }

        integral /= static_cast<double>(sample_count);

        return integral;
    }
Пример #6
0
        static void evaluate_fr_spec(
            const MDF&          mdf,
            const Spectrum&     rs,
            const double        dot_HL,     // cos_beta in the paper
            const double        dot_HN,
            Spectrum&           fr_spec)
        {
            assert(dot_HL >= 0.0);
            assert(dot_HN >= 0.0);

            fr_spec = fresnel_dielectric_schlick(rs, dot_HL);
            fr_spec *= static_cast<float>(mdf.evaluate(dot_HN) / (4.0 * dot_HL * dot_HL));
        }
Пример #7
0
    bool is_positive(
        const MDF&      mdf,
        const size_t    sample_count)
    {
        for (size_t i = 0; i < sample_count; ++i)
        {
            const double theta = radical_inverse_base2<double>(i) * HalfPi;
            const double cos_theta = cos(theta);

            const double value = mdf.evaluate(cos_theta);

            if (value < 0.0)
                return false;
        }

        return true;
    }
Пример #8
0
    bool is_positive(
        const MDF&                      mdf,
        const typename MDF::ValueType   alpha_x,
        const typename MDF::ValueType   alpha_y,
        const size_t                    sample_count)
    {
        for (size_t i = 0; i < sample_count; ++i)
        {
            static const size_t Bases[] = { 2 };
            const Vector2d s = hammersley_sequence<double, 2>(Bases, sample_count, i);

            const Vector<typename MDF::ValueType, 3> h = sample_hemisphere_uniform(s);
            const double value = mdf.D(h, alpha_x, alpha_y);

            if (value < 0.0)
                return false;
        }

        return true;
    }
Пример #9
0
    bool is_positive(
        const MDF&    mdf,
        const float   alpha_x,
        const float   alpha_y,
        const size_t  sample_count,
        const float   gamma = 0.0f)
    {
        for (size_t i = 0; i < sample_count; ++i)
        {
            static const size_t Bases[] = { 2 };
            const Vector2f s = hammersley_sequence<float, 2>(Bases, sample_count, i);

            const Vector3f h = sample_hemisphere_uniform(s);
            const float value = mdf.D(h, alpha_x, alpha_y, gamma);

            if (value < 0.0f)
                return false;
        }

        return true;
    }
Пример #10
0
    float integrate(
        const MDF&    mdf,
        const float   alpha,
        const size_t  sample_count,
        const float   gamma = 0.0f)
    {
        float integral = 0.0f;

        for (size_t i = 0; i < sample_count; ++i)
        {
            const float theta = radical_inverse_base2<float>(i) * HalfPi<float>();
            const Vector3f h(0.0f, cos(theta), 0.0f);
            const float value = mdf.D(h, alpha, alpha, gamma);

            integral += value * h.y * sin(theta);
        }

        integral *= HalfPi<float>() / sample_count;     // integration over theta
        integral *= TwoPi<float>();                     // integration over phi

        return integral;
    }
Пример #11
0
    double integrate_quadrature(
        const MDF&      mdf,
        const size_t    sample_count)
    {
        double integral = 0.0;

        for (size_t i = 0; i < sample_count; ++i)
        {
            const double theta = radical_inverse_base2<double>(i) * HalfPi;
            const double cos_theta = cos(theta);
            const double sin_theta = sin(theta);

            const double value = mdf.evaluate(cos_theta);

            integral += value * cos_theta * sin_theta;
        }

        integral *= HalfPi / sample_count;  // integration over theta
        integral *= TwoPi;                  // integration over phi

        return integral;
    }
Пример #12
0
    typename MDF::ValueType integrate(
        const MDF&                      mdf,
        const typename MDF::ValueType   alpha,
        const size_t                    sample_count)
    {
        typedef typename MDF::ValueType ValueType;

        ValueType integral = ValueType(0.0);

        for (size_t i = 0; i < sample_count; ++i)
        {
            const ValueType theta = radical_inverse_base2<ValueType>(i) * HalfPi<ValueType>();
            const Vector<ValueType, 3> h(ValueType(0.0), cos(theta), ValueType(0.0));
            const ValueType value = mdf.D(h, alpha, alpha);

            integral += value * h.y * sin(theta);
        }

        integral *= HalfPi<ValueType>() / sample_count;     // integration over theta
        integral *= TwoPi<ValueType>();                     // integration over phi

        return integral;
    }