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))); }
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_triangle_sample_contribution( const LightSample& sample, const MISHeuristic mis_heuristic, const Dual3d& outgoing, Spectrum& radiance, SpectrumStack& aovs) const { const Material* material = sample.m_triangle->m_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_point; // Cull light samples behind the shading surface if the BSDF is either reflective or transmissive, // but not both. if (m_bsdf.get_type() != BSDF::AllBSDFTypes) { double cos_in = dot(incoming, m_shading_basis.get_normal()); if (m_bsdf.get_type() == BSDF::Transmissive) cos_in = -cos_in; if (cos_in <= 0.0) return; } // 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 transmission factor between the light sample and the shading point. const double transmission = m_shading_context.get_tracer().trace_between( m_shading_point, sample.m_point, VisibilityFlags::ShadowRay); // Discard occluded samples. if (transmission == 0.0) return; // Compute the square distance between the light sample and the shading point. const double square_distance = square_norm(incoming); const double rcp_sample_square_distance = 1.0 / square_distance; const double rcp_sample_distance = sqrt(rcp_sample_square_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; // Normalize the incoming direction. incoming *= rcp_sample_distance; cos_on *= rcp_sample_distance; // Evaluate the BSDF. Spectrum bsdf_value; const double bsdf_prob = m_bsdf.evaluate( m_bsdf_data, false, // not adjoint true, // multiply by |cos(incoming, normal)| m_geometric_normal, m_shading_basis, outgoing.get_value(), incoming, m_light_sampling_modes, bsdf_value); if (bsdf_prob == 0.0) 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()); #ifdef APPLESEED_WITH_OSL if (material_data.m_shader_group) { m_shading_context.execute_osl_emission( *material_data.m_shader_group, light_shading_point); } #endif // Evaluate the EDF inputs. InputEvaluator edf_input_evaluator(m_shading_context.get_texture_cache()); edf->evaluate_inputs(edf_input_evaluator, light_shading_point); // Evaluate the EDF. Spectrum edf_value; edf->evaluate( edf_input_evaluator.data(), sample.m_geometric_normal, Basis3d(sample.m_shading_normal), -incoming, edf_value); const double g = cos_on * rcp_sample_square_distance; double weight = transmission * g / sample.m_probability; // Apply MIS weighting. weight *= mis( mis_heuristic, m_light_sample_count * sample.m_probability, m_bsdf_sample_count * bsdf_prob * g); // Add the contribution of this sample to the illumination. edf_value *= static_cast<float>(weight); edf_value *= bsdf_value; radiance += edf_value; aovs.add(edf->get_render_layer_index(), edf_value); }
bool DirectLightingIntegrator::compute_incoming_radiance( SamplingContext& sampling_context, Vector3d& incoming, double& incoming_prob, Spectrum& radiance) const { if (!m_light_sampler.has_lights_or_emitting_triangles()) return false; sampling_context.split_in_place(3, 1); const Vector3d s = sampling_context.next_vector2<3>(); LightSample sample; m_light_sampler.sample(m_time, s, sample); if (sample.m_triangle) { const Material* material = sample.m_triangle->m_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 false; // Compute the incoming direction in world space. incoming = sample.m_point - m_point; // No contribution if the shading point is behind the light. double cos_on_light = dot(-incoming, sample.m_shading_normal); if (cos_on_light <= 0.0) return false; // Compute the transmission factor between the light sample and the shading point. const double transmission = m_shading_context.get_tracer().trace_between( m_shading_point, sample.m_point, VisibilityFlags::ShadowRay); // Discard occluded samples. if (transmission == 0.0) return false; // Don't use this sample if we're closer than the light near start value. const double square_distance = square_norm(incoming); if (square_distance < square(edf->get_light_near_start())) return false; // Normalize the incoming direction. const double rcp_square_distance = 1.0 / square_distance; const double rcp_distance = sqrt(rcp_square_distance); incoming *= rcp_distance; cos_on_light *= rcp_distance; // 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()); #ifdef APPLESEED_WITH_OSL if (material_data.m_shader_group) { m_shading_context.execute_osl_emission( *material_data.m_shader_group, light_shading_point); } #endif // Evaluate the EDF inputs. InputEvaluator edf_input_evaluator(m_shading_context.get_texture_cache()); edf->evaluate_inputs(edf_input_evaluator, light_shading_point); // Evaluate the EDF. edf->evaluate( edf_input_evaluator.data(), sample.m_geometric_normal, Basis3d(sample.m_shading_normal), -incoming, radiance); // Compute probability with respect to solid angle of incoming direction. const double g = cos_on_light * rcp_square_distance; incoming_prob = sample.m_probability / g; // Compute and return the incoming radiance. radiance *= static_cast<float>(transmission * g / sample.m_probability); } else { const Light* light = sample.m_light; // No contribution if we are computing indirect lighting but this light does not cast indirect light. if (m_indirect && !(light->get_flags() & Light::CastIndirectLight)) return false; // Evaluate the light. InputEvaluator input_evaluator(m_shading_context.get_texture_cache()); Vector3d emission_position, emission_direction; light->evaluate( input_evaluator, sample.m_light_transform, m_point, emission_position, emission_direction, radiance); // Compute the transmission factor between the light sample and the shading point. const double transmission = m_shading_context.get_tracer().trace_between( m_shading_point, emission_position, VisibilityFlags::ShadowRay); // Discard occluded samples. if (transmission == 0.0) return false; // Compute the incoming direction in world space. incoming = -emission_direction; incoming_prob = BSDF::DiracDelta; // Compute and return the incoming radiance. const double attenuation = light->compute_distance_attenuation(m_point, emission_position); radiance *= static_cast<float>(transmission * attenuation / sample.m_probability); } return true; }