Exemplo n.º 1
0
void PathVertex::compute_emitted_radiance(
    const ShadingContext&   shading_context,
    TextureCache&           texture_cache,
    Spectrum&               radiance) const
{
    assert(m_edf);

    // No radiance if we're too close to the light.
    if (m_shading_point->get_distance() < m_edf->get_light_near_start())
    {
        radiance.set(0.0f);
        return;
    }

    if (const ShaderGroup* sg = get_material()->get_render_data().m_shader_group)
        shading_context.execute_osl_emission(*sg, *m_shading_point);

    // Evaluate the EDF inputs.
    InputEvaluator input_evaluator(texture_cache);
    m_edf->evaluate_inputs(input_evaluator, *m_shading_point);

    // Compute the emitted radiance.
    m_edf->evaluate(
        input_evaluator.data(),
        Vector3f(m_shading_point->get_geometric_normal()),
        Basis3f(m_shading_point->get_shading_basis()),
        Vector3f(m_outgoing.get_value()),
        radiance);
}
Exemplo n.º 2
0
void OSLShaderGroupExec::choose_bsdf_closure_shading_basis(
    const ShadingPoint&             shading_point,
    const Vector2f&                 s) const
{
    CompositeSurfaceClosure c(
        Basis3f(shading_point.get_shading_basis()),
        shading_point.get_osl_shader_globals().Ci,
        m_arena);

    float pdfs[CompositeSurfaceClosure::MaxClosureEntries];
    const size_t num_closures = c.compute_pdfs(ScatteringMode::All, pdfs);
    if (num_closures == 0)
        return;

    const size_t index = c.choose_closure(s[1], num_closures, pdfs);
    shading_point.set_shading_basis(
        Basis3d(c.get_closure_shading_basis(index)));
}
Exemplo n.º 3
0
void OSLShaderGroupExec::execute_bump(
    const ShaderGroup&              shader_group,
    const ShadingPoint&             shading_point,
    const Vector2f&                 s) const
{
    // Choose between BSSRDF and BSDF.
    if (shader_group.has_subsurface() && s[0] < 0.5f)
    {
        do_execute(
            shader_group,
            shading_point,
            VisibilityFlags::SubsurfaceRay);

        CompositeSubsurfaceClosure c(
            Basis3f(shading_point.get_shading_basis()),
            shading_point.get_osl_shader_globals().Ci,
            m_arena);

        // Pick a shading basis from one of the BSSRDF closures.
        if (c.get_closure_count() > 0)
        {
            const size_t index = c.choose_closure(s[1]);
            shading_point.set_shading_basis(
                Basis3d(c.get_closure_shading_basis(index)));
        }
    }
    else
    {
        do_execute(
            shader_group,
            shading_point,
            VisibilityFlags::CameraRay);

        choose_bsdf_closure_shading_basis(shading_point, s);
    }
}
void DirectLightingIntegrator::add_emitting_shape_sample_contribution(
    SamplingContext&                sampling_context,
    const LightSample&              sample,
    const MISHeuristic              mis_heuristic,
    const Dual3d&                   outgoing,
    DirectShadingComponents&        radiance,
    LightPathStream*                light_path_stream) const
{
    const Material* material = sample.m_shape->get_material();
    const Material::RenderData& material_data = material->get_render_data();
    const EDF* edf = material_data.m_edf;

    // No contribution if we are computing indirect lighting but this light does not cast indirect light.
    if (m_indirect && !(edf->get_flags() & EDF::CastIndirectLight))
        return;

    // Compute the incoming direction in world space.
    Vector3d incoming = sample.m_point - m_material_sampler.get_point();

    // No contribution if the shading point is behind the light.
    double cos_on = dot(-incoming, sample.m_shading_normal);
    if (cos_on <= 0.0)
        return;

    // Compute the square distance between the light sample and the shading point.
    const double square_distance = square_norm(incoming);

    // Don't use this sample if we're closer than the light near start value.
    if (square_distance < square(edf->get_light_near_start()))
        return;

    const double rcp_sample_square_distance = 1.0 / square_distance;
    const double rcp_sample_distance = sqrt(rcp_sample_square_distance);

    // Normalize the incoming direction.
    cos_on *= rcp_sample_distance;
    incoming *= rcp_sample_distance;

    // Probabilistically skip light samples with low maximum contribution.
    float contribution_prob = 1.0f;
    if (m_low_light_threshold > 0.0f)
    {
        // Compute the approximate maximum contribution of this light sample.
        const float max_contribution =
            static_cast<float>(
                cos_on *
                rcp_sample_square_distance *
                sample.m_shape->get_max_flux());

        // Use Russian Roulette to skip this sample if its maximum contribution is low.
        if (max_contribution < m_low_light_threshold)
        {
            // Generate a uniform sample in [0,1).
            SamplingContext child_sampling_context = sampling_context.split(1, 1);
            const float s = child_sampling_context.next2<float>();

            // Compute the probability of taking the sample's contribution into account.
            contribution_prob = max_contribution / m_low_light_threshold;

            // Russian Roulette.
            if (!pass_rr(contribution_prob, s))
                return;
        }
    }

    // Compute the transmission factor between the light sample and the shading point.
    Spectrum transmission;
    m_material_sampler.trace_between(
        m_shading_context,
        sample.m_point,
        transmission);

    // Discard occluded samples.
    if (is_zero(transmission))
        return;

    // Evaluate the BSDF (or volume).
    DirectShadingComponents material_value;
    const float material_probability =
        m_material_sampler.evaluate(
            Vector3f(outgoing.get_value()),
            Vector3f(incoming),
            m_light_sampling_modes,
            material_value);
    assert(material_probability >= 0.0f);
    if (material_probability == 0.0f)
        return;

    // Build a shading point on the light source.
    ShadingPoint light_shading_point;
    sample.make_shading_point(
        light_shading_point,
        sample.m_shading_normal,
        m_shading_context.get_intersector());

    if (material_data.m_shader_group)
    {
        m_shading_context.execute_osl_emission(
            *material_data.m_shader_group,
            light_shading_point);
    }

    // Evaluate the EDF.
    Spectrum edf_value(Spectrum::Illuminance);
    edf->evaluate(
        edf->evaluate_inputs(m_shading_context, light_shading_point),
        Vector3f(sample.m_geometric_normal),
        Basis3f(Vector3f(sample.m_shading_normal)),
        -Vector3f(incoming),
        edf_value);

    const float g = static_cast<float>(cos_on * rcp_sample_square_distance);

    // Apply MIS weighting.
    const float mis_weight =
        mis(
            mis_heuristic,
            m_light_sample_count * sample.m_probability,
            m_material_sample_count * material_probability * g);

    // Add the contribution of this sample to the illumination.
    edf_value *= transmission;
    edf_value *= (mis_weight * g) / (sample.m_probability * contribution_prob);
    madd(radiance, material_value, edf_value);

    // Record light path event.
    if (light_path_stream)
    {
        light_path_stream->sampled_emitting_shape(
            *sample.m_shape,
            sample.m_point,
            material_value.m_beauty,
            edf_value);
    }
}
void DirectLightingIntegrator::take_single_material_sample(
    SamplingContext&                sampling_context,
    const MISHeuristic              mis_heuristic,
    const Dual3d&                   outgoing,
    DirectShadingComponents&        radiance) const
{
    assert(m_light_sampler.has_hittable_lights());

    // Sample material.
    Dual3f incoming;
    DirectShadingComponents sample_value;
    float sample_probability;
    if (!m_material_sampler.sample(
            sampling_context,
            outgoing,
            incoming,
            sample_value,
            sample_probability))
        return;

    // Trace a ray in the direction of the reflection.
    Spectrum weight;
    const ShadingPoint& light_shading_point =
        m_material_sampler.trace_full(
            m_shading_context,
            incoming.get_value(),
            weight);

    // todo: wouldn't it be more efficient to look the environment up at this point?
    if (!light_shading_point.hit_surface())
        return;

    // Retrieve the material at the intersection point.
    const Material* material = light_shading_point.get_material();
    if (material == nullptr)
        return;
    const Material::RenderData& material_data = material->get_render_data();

    // Retrieve the EDF at the intersection point.
    const EDF* edf = material_data.m_edf;
    if (edf == nullptr)
        return;

    // No contribution if we are computing indirect lighting but this light does not cast indirect light.
    if (m_indirect && !(edf->get_flags() & EDF::CastIndirectLight))
        return;

    // Cull the samples on the back side of the lights' shading surface.
    const float cos_on = dot(-incoming.get_value(), Vector3f(light_shading_point.get_shading_normal()));
    if (cos_on <= 0.0f)
        return;

    if (material_data.m_shader_group)
    {
        m_shading_context.execute_osl_emission(
            *material_data.m_shader_group,
            light_shading_point);
    }

    // Evaluate emitted radiance.
    Spectrum edf_value(Spectrum::Illuminance);
    float edf_prob;
    edf->evaluate(
        edf->evaluate_inputs(m_shading_context, light_shading_point),
        Vector3f(light_shading_point.get_geometric_normal()),
        Basis3f(light_shading_point.get_shading_basis()),
        -incoming.get_value(),
        edf_value,
        edf_prob);
    if (edf_prob == 0.0f)
        return;

    // Compute the square distance between the light sample and the shading point.
    const double square_distance = square(light_shading_point.get_distance());

    // Don't use this sample if we're closer than the light near start value.
    if (square_distance < square(edf->get_light_near_start()))
        return;

    if (sample_probability != BSDF::DiracDelta)
    {
        if (mis_heuristic != MISNone && square_distance > 0.0)
        {
            // Transform material_prob to surface area measure (Veach: 8.2.2.2 eq. 8.10).
            const float material_prob_area = sample_probability * cos_on / static_cast<float>(square_distance);

            // Compute the probability density wrt. surface area measure of the light sample.
            const float light_prob_area = m_light_sampler.evaluate_pdf(
                light_shading_point, m_material_sampler.get_shading_point());

            // Apply the weighting function.
            weight *=
                mis(
                    mis_heuristic,
                    m_material_sample_count * material_prob_area,
                    m_light_sample_count * light_prob_area);
        }

        edf_value *= weight / sample_probability;
    }
    else
    {
        edf_value *= weight;
    }

    // Add the contribution of this sample to the illumination.
    madd(radiance, sample_value, edf_value);
}