use crate::core::scene::BasicScene; use crate::globals::get_options; use crate::integrators::pipeline::render; use crate::Arena; use anyhow::{bail, Result}; use log::warn; use shared::core::camera::CameraTrait; use shared::core::geometry::{Point2f, Vector2f}; use shared::core::interaction::InteractionTrait; use shared::core::primitive::PrimitiveTrait; use shared::core::sampler::CameraSample; use shared::spectra::{SampledWavelengths, LAMBDA_MAX, LAMBDA_MIN}; use crate::wavefront::integrator::CpuWavefrontRenderer; use shared::Float; pub fn render_scene(scene: &BasicScene, arena: &Arena) -> Result<()> { let media = scene.create_media(); let textures = scene.create_textures(arena); let (named_materials, materials) = scene.create_materials(&textures, arena)?; let (lights, al_map) = scene.create_lights(&textures, &media, arena); let _have_scattering = { let shapes = scene.shapes.lock(); let animated = scene.animated_shapes.lock(); shapes .iter() .any(|sh| !sh.inside_medium.is_empty() || !sh.outside_medium.is_empty()) || animated .iter() .any(|sh| !sh.inside_medium.is_empty() || !sh.outside_medium.is_empty()) }; let aggregate = scene.create_aggregate(&textures, &named_materials, &materials, al_map, &media, arena); let mut all_lights = lights; all_lights.extend(area_lights); let camera = scene.get_camera().unwrap(); let _film = camera.get_film(); warn!("Creating integrator"); let sampler = scene.get_sampler()?; if get_options().pixel_material.is_some() { let lambda = SampledWavelengths::sample_uniform(0.5, LAMBDA_MIN as Float, LAMBDA_MAX as Float); let cs = CameraSample { p_film: Point2f::from(get_options().pixel_material.unwrap()) + Vector2f::new(0.5, 0.5), time: 0.5, p_lens: Point2f::new(0.5, 0.5), filter_weight: 1., }; let Some(cr) = camera.generate_ray_differential(cs, &lambda) else { bail!("Unable to generate ray for pixel") }; let mut depth = 1; let mut ray = cr.ray; loop { if let Some(isect) = aggregate.intersect(&ray, Some(Float::INFINITY)) { let intr = isect.intr; if intr.material.is_none() { log::warn!("Ignoring material") } else { let world_from_render = camera.base().camera_transform.world_from_render; log::debug!("Intersection depth {}\n", depth); log::debug!( "World-space p: {}\n", world_from_render.apply_to_point(intr.p()) ); log::debug!( "World-space n: {}\n", world_from_render.apply_to_normal(intr.n()) ); log::debug!( "World-space ns: {}\n", world_from_render.apply_to_normal(intr.shading.n) ); log::debug!("Distance from camera: {}\n", intr.p().distance(cr.ray.o)); for (name, mtl) in &named_materials { if *mtl == intr.material { log::debug!("Named material: {}\n\n", name); break; } } depth += 1; ray = intr.spawn_ray(ray.d); } } else if depth == 1 { bail!("No geometry visible from pixel") } else { break; } } } if get_options().wavefront { eprintln!("RENDER: Wavefront backend"); let mut wf = scene.create_wavefront_integrator( camera.clone(), sampler.clone(), aggregate.clone(), all_lights, materials, arena, ); wf.render(); } else { eprintln!("RENDER: Path integrator backend"); let integrator = scene.create_integrator( camera.clone(), sampler.clone(), aggregate.clone(), all_lights, arena, ); render( &integrator, &integrator.base, &camera, sampler.as_ref(), arena, ); } Ok(()) }