129 lines
4.4 KiB
Rust
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(())
|
|
}
|