enginerenderer 0.0.1

A zero-dependency offline rendering engine in pure Rust — CPU path tracing, BVH acceleration, 16-band spectral rendering, PBR materials, animation & video export.
Documentation
use super::hrtf::HrtfProcessor;
use super::mixer::{AudioChannel, AudioMixer};
use super::reverb::{ReverbProcessor, RoomConfig};
use crate::core::engine::scene::graph::SceneGraph;

#[derive(Debug, Clone, Copy)]
pub struct AudioMix {
    pub master_gain: f64,
    pub spatial_width: f64,
    pub reverb_send: f64,
}

#[derive(Debug, Clone, Copy)]
pub struct AudioManager {
    base_gain: f64,
}

impl AudioManager {
    pub fn new(base_gain: f64) -> Self {
        Self {
            base_gain: base_gain.clamp(0.1, 2.0),
        }
    }

    pub fn mix_for_scene(
        &self,
        graph: &SceneGraph,
        camera_distance: f64,
        exposure_bias: f64,
    ) -> AudioMix {
        let luminous_factor = graph.luminous_node_count().max(1) as f64;
        let distance_factor = (camera_distance / (graph.scene_radius() + 1.0)).clamp(0.5, 2.0);

        AudioMix {
            master_gain: self.base_gain * (0.85 + luminous_factor * 0.03) / distance_factor,
            spatial_width: (0.55 + graph.node_count() as f64 * 0.04).clamp(0.55, 1.0),
            reverb_send: (0.12 + exposure_bias * 0.18).clamp(0.1, 0.4),
        }
    }

    pub fn spatialize(
        &self,
        mono: &[f32],
        azimuth: f64,
        elevation: f64,
        sample_rate: u32,
    ) -> Vec<[f32; 2]> {
        let hrtf = HrtfProcessor::new(0.0875, sample_rate);
        hrtf.process(mono, azimuth, elevation)
    }

    pub fn apply_reverb(
        &self,
        mono: &[f32],
        source: [f64; 3],
        listener: [f64; 3],
        room_size: f64,
        sample_rate: u32,
    ) -> Vec<[f32; 2]> {
        let reverb = ReverbProcessor::new(
            RoomConfig {
                width: room_size,
                height: room_size * 0.6,
                depth: room_size,
                absorption: 0.3,
            },
            sample_rate,
        );
        reverb.process(mono, source, listener)
    }

    pub fn mix_sources(
        &self,
        sources: Vec<(Vec<f32>, f64, f64)>,
        sample_rate: u32,
    ) -> Vec<[f32; 2]> {
        let mut mixer = AudioMixer::new(sample_rate);
        for (buffer, gain, pan) in sources {
            mixer.add_channel(AudioChannel::new(buffer, gain * self.base_gain, pan));
        }
        mixer.mix_to_stereo()
    }
}