pbrt/src/core/render.rs
2026-06-08 16:32:59 +01:00

129 lines
4.4 KiB
Rust

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(())
}