Example #1
0
        FORCE_INLINE virtual double evaluate(
            const void*         data,
            const bool          adjoint,
            const bool          cosine_mult,
            const Vector3d&     geometric_normal,
            const Basis3d&      shading_basis,
            const Vector3d&     outgoing,
            const Vector3d&     incoming,
            const int           modes,
            Spectrum&           value) const
        {
            if (!(modes & BSDFSample::Diffuse))
                return 0.0;

            const Vector3d& n = shading_basis.get_normal();
            const double cos_in = abs(dot(incoming, n));

            // Compute the BRDF value.
            const InputValues* values = static_cast<const InputValues*>(data);
            value = values->m_transmittance;
            value *= static_cast<float>(values->m_transmittance_multiplier * RcpPi);

            // Return the probability density of the sampled direction.
            return cos_in * RcpPi;
        }
Example #2
0
double compute_fast_ambient_occlusion(
    const SamplingContext&          sampling_context,
    const AOVoxelTreeIntersector&   intersector,
    const Vector3d&                 point,
    const Vector3d&                 geometric_normal,
    const Basis3d&                  shading_basis,
    const double                    max_distance,
    const size_t                    sample_count,
    double&                         min_distance)
{
    // Create a sampling context.
    SamplingContext child_sampling_context = sampling_context.split(2, sample_count);

    // Construct the ambient occlusion ray.
    ShadingRay::RayType ray;
    ray.m_org = point;
    ray.m_tmin = 0.0;
    ray.m_tmax = max_distance;

    size_t computed_samples = 0;
    size_t occluded_samples = 0;

    min_distance = max_distance;

    for (size_t i = 0; i < sample_count; ++i)
    {
        // Generate a cosine-weighted direction over the unit hemisphere.
        ray.m_dir = sample_hemisphere_cosine(child_sampling_context.next_vector2<2>());

        // Transform the direction to world space.
        ray.m_dir = shading_basis.transform_to_parent(ray.m_dir);

        // Don't cast rays on or below the geometric surface.
        if (dot(ray.m_dir, geometric_normal) <= 0.0)
            continue;

        // Count the number of computed samples.
        ++computed_samples;

        // Trace the ambient occlusion ray and count the number of occluded samples.
        double distance;
        if (intersector.trace(ray, true, distance))
        {
            ++occluded_samples;
            min_distance = min(min_distance, distance);
        }
    }

    // Compute occlusion as a scalar between 0.0 and 1.0.
    double occlusion = static_cast<double>(occluded_samples);
    if (computed_samples > 1)
        occlusion /= computed_samples;
    assert(occlusion >= 0.0);
    assert(occlusion <= 1.0);

    return occlusion;
}
        FORCE_INLINE virtual double evaluate_pdf(
            const void*         data,
            const Vector3d&     geometric_normal,
            const Basis3d&      shading_basis,
            const Vector3d&     outgoing,
            const Vector3d&     incoming,
            const int           modes) const
        {
            if (!(modes & Glossy))
                return 0.0;

            // If incoming and outgoing are on the same hemisphere
            // this is not a refraction.
            const Vector3d& n = shading_basis.get_normal();
            if (dot(incoming, n) * dot(outgoing, n) >= 0.0)
                return Absorption;

            const InputValues* values = static_cast<const InputValues*>(data);

            double ht_norm;
            const Vector3d ht = half_refraction_vector(
                outgoing,
                incoming,
                n,
                values->m_from_ior,
                values->m_to_ior,
                ht_norm);

            const Vector3d m = shading_basis.transform_to_local(ht);
            const double dwh_dwo = refraction_jacobian(
                incoming,
                values->m_to_ior,
                ht,
                ht_norm);

            return m_mdf->pdf(m, values->m_ax, values->m_ay) * dwh_dwo;
        }
Example #4
0
        FORCE_INLINE virtual double evaluate_pdf(
            const void*         data,
            const Vector3d&     geometric_normal,
            const Basis3d&      shading_basis,
            const Vector3d&     outgoing,
            const Vector3d&     incoming,
            const int           modes) const
        {
            if (!(modes & BSDFSample::Diffuse))
                return 0.0;

            const Vector3d& n = shading_basis.get_normal();
            const double cos_in = abs(dot(incoming, n));

            return cos_in * RcpPi;
        }
Example #5
0
        size_t generate_environment_sample(
            SamplingContext&            sampling_context,
            const EnvironmentEDF*       env_edf,
            SampleVector&               samples)
        {
            // Sample the environment.
            sampling_context.split_in_place(2, 1);
            InputEvaluator input_evaluator(m_texture_cache);
            Vector3f outgoing;
            Spectrum env_edf_value;
            float env_edf_prob;
            env_edf->sample(
                m_shading_context,
                input_evaluator,
                sampling_context.next2<Vector2f>(),
                outgoing,               // points toward the environment
                env_edf_value,
                env_edf_prob);

            // Uniformly sample the tangent disk.
            sampling_context.split_in_place(2, 1);
            const Vector2d p =
                  m_scene_radius
                * sample_disk_uniform(sampling_context.next2<Vector2d>());

            // Compute the origin of the light ray.
            const Basis3d basis(-Vector3d(outgoing));
            const Vector3d ray_origin =
                  m_scene_center
                - m_safe_scene_diameter * basis.get_normal()    // a safe radius would have been sufficient
                + p[0] * basis.get_tangent_u() +
                + p[1] * basis.get_tangent_v();

            // Compute the initial particle weight.
            Spectrum initial_flux = env_edf_value;
            initial_flux /= m_disk_point_prob * env_edf_prob;

            // Build the light ray.
            sampling_context.split_in_place(1, 1);
            const ShadingRay::Time time =
                ShadingRay::Time::create_with_normalized_time(
                    sampling_context.next2<float>(),
                    m_shutter_open_time,
                    m_shutter_close_time);
            const ShadingRay light_ray(
                ray_origin,
                -Vector3d(outgoing),
                time,
                VisibilityFlags::LightRay,
                0);

            // Build the path tracer.
            PathVisitor path_visitor(
                m_params,
                m_scene,
                m_frame,
                m_shading_context,
                sampling_context,
                samples,
                initial_flux);
            PathTracerType path_tracer(
                path_visitor,
                m_params.m_rr_min_path_length,
                m_params.m_max_path_length,
                m_params.m_max_iterations);

            // Trace the light path.
            const size_t path_length =
                path_tracer.trace(
                    sampling_context,
                    m_shading_context,
                    light_ray);

            // Update path statistics.
            ++m_path_count;
            m_path_length.insert(path_length);

            // Return the number of samples generated when tracing this light path.
            return path_visitor.get_sample_count();
        }
        size_t generate_environment_sample(
            SamplingContext&            sampling_context,
            const EnvironmentEDF*       env_edf,
            SampleVector&               samples)
        {
            // Sample the environment.
            sampling_context.split_in_place(2, 1);
            InputEvaluator input_evaluator(m_texture_cache);
            Vector3d outgoing;
            Spectrum env_edf_value;
            double env_edf_prob;
            env_edf->sample(
                input_evaluator,
                sampling_context.next_vector2<2>(),
                outgoing,               // points toward the environment
                env_edf_value,
                env_edf_prob);

            // Compute the center of the tangent disk.
            const Vector3d disk_center = m_safe_scene_radius * outgoing;

            // Uniformly sample the tangent disk.
            sampling_context.split_in_place(2, 1);
            const Vector2d disk_point =
                m_safe_scene_radius *
                sample_disk_uniform(sampling_context.next_vector2<2>());

            // Compute the origin of the light ray.
            const Basis3d basis(-outgoing);
            const Vector3d ray_origin =
                disk_center +
                disk_point[0] * basis.get_tangent_u() +
                disk_point[1] * basis.get_tangent_v();

            // Compute the initial particle weight.
            Spectrum initial_flux = env_edf_value;
            initial_flux /= static_cast<float>(m_disk_point_prob * env_edf_prob);

            // Build the light ray.
            sampling_context.split_in_place(1, 1);
            const ShadingRay light_ray(
                ray_origin,
                -outgoing,
                sampling_context.next_double2(),
                m_ray_dtime,
                ShadingRay::LightRay);

            // Build the path tracer.
            PathVisitor path_visitor(
                m_params,
                m_scene,
                m_frame,
                m_shading_context,
                samples,
                initial_flux);
            PathTracerType path_tracer(
                path_visitor,
                m_params.m_rr_min_path_length,
                m_params.m_max_path_length,
                m_params.m_max_iterations);

            // Trace the light path.
            const size_t path_length =
                path_tracer.trace(
                    sampling_context,
                    m_shading_context,
                    light_ray);

            // Update path statistics.
            ++m_path_count;
            m_path_length.insert(path_length);

            // Return the number of samples generated when tracing this light path.
            return path_visitor.get_sample_count();
        }
        FORCE_INLINE virtual double evaluate(
            const void*         data,
            const bool          adjoint,
            const bool          cosine_mult,
            const Vector3d&     geometric_normal,
            const Basis3d&      shading_basis,
            const Vector3d&     outgoing,
            const Vector3d&     incoming,
            const int           modes,
            Spectrum&           value) const
        {
            if (!(modes & Glossy))
                return 0.0;

            // If incoming and outgoing are on the same hemisphere
            // this is not a refraction.
            const Vector3d& n = shading_basis.get_normal();
            if (dot(incoming, n) * dot(outgoing, n) >= 0.0)
                return Absorption;

            const InputValues* values = static_cast<const InputValues*>(data);

            double ht_norm;
            const Vector3d ht = half_refraction_vector(
                outgoing,
                incoming,
                n,
                values->m_from_ior,
                values->m_to_ior,
                ht_norm);

            const Vector3d m = shading_basis.transform_to_local(ht);

            const double G =
                m_mdf->G(
                    shading_basis.transform_to_local(incoming),
                    shading_basis.transform_to_local(outgoing),
                    m,
                    values->m_ax,
                    values->m_ay);

            if (G == 0.0)
                return 0.0;

            const double D = m_mdf->D(m, values->m_ax, values->m_ay);

            const double cos_oh = dot(outgoing, ht);
            const double cos_ih = dot(incoming, ht);
            const double cos_in = dot(incoming, n);
            const double cos_on = dot(outgoing, n);
 
            // [1] equation 21.
            double v = abs((cos_ih * cos_oh) / (cos_in * cos_on));
            v *= square(values->m_to_ior) * D * G;
            const double denom = values->m_to_ior * cos_ih + values->m_from_ior * cos_oh;
            v /= square(denom);
            value.set(static_cast<float>(v));

            const double dwh_dwo = refraction_jacobian(
                incoming,
                values->m_to_ior,
                ht,
                ht_norm);

            return m_mdf->pdf(m, values->m_ax, values->m_ay) * dwh_dwo;
        }
        FORCE_INLINE virtual Mode sample(
            SamplingContext&    sampling_context,
            const void*         data,
            const bool          adjoint,
            const bool          cosine_mult,
            const Vector3d&     geometric_normal,
            const Basis3d&      shading_basis,
            const Vector3d&     outgoing,
            Vector3d&           incoming,
            Spectrum&           value,
            double&             probability) const
        {
            const InputValues* values = static_cast<const InputValues*>(data);

            // Compute the incoming direction by sampling the MDF.
            sampling_context.split_in_place(2, 1);
            const Vector2d s = sampling_context.next_vector2<2>();
            const Vector3d m = m_mdf->sample(s, values->m_ax, values->m_ay);
            const Vector3d ht = shading_basis.transform_to_parent(m);

            if (!refract(
                    outgoing,
                    ht,
                    values->m_from_ior / values->m_to_ior,
                    incoming))
            {
                // Ignore TIR.
                return Absorption;
            }

            // If incoming and outgoing are on the same hemisphere
            // this is not a refraction.
            const Vector3d& n = shading_basis.get_normal();
            if (dot(incoming, n) * dot(outgoing, n) >= 0.0)
                return Absorption;

            const double G =
                m_mdf->G(
                    shading_basis.transform_to_local(incoming),
                    shading_basis.transform_to_local(outgoing),
                    m,
                    values->m_ax,
                    values->m_ay);

            if (G == 0.0)
                return Absorption;

            const double D = m_mdf->D(m, values->m_ax, values->m_ay);

            const double cos_oh = dot(outgoing, ht);
            const double cos_ih = dot(incoming, ht);
            const double cos_in = dot(incoming, n);
            const double cos_on = dot(outgoing, n);
 
            // [1] equation 21.
            double v = abs((cos_ih * cos_oh) / (cos_in * cos_on));
            v *= square(values->m_to_ior) * D * G;
            const double denom = values->m_to_ior * cos_ih + values->m_from_ior * cos_oh;
            v /= square(denom);
            value.set(static_cast<float>(v));

            const double ht_norm = norm(values->m_from_ior * outgoing + values->m_to_ior * incoming);
            const double dwh_dwo = refraction_jacobian(
                incoming,
                values->m_to_ior,
                ht,
                ht_norm);

            probability = m_mdf->pdf(m, values->m_ax, values->m_ay) * dwh_dwo;
            return Glossy;
        }