//! **Cielo de noche**: estrellas, luna y la luz que dan. //! //! Vive en la escena y no en el sello de quien filma porque **que sea de noche //! lo dice el cuento**: «la princesa vio una estrella» no se puede filmar a //! pleno sol, la ruede la marca que la ruede. El sello sigue decidiendo la luz //! de día; una escena con cielo de noche la reemplaza por la suya. //! //! De noche la dirección del sol pasa a ser la de **la luna** (el shader dibuja //! el disco pálido ahí y de ahí viene la luz directa, fría y tenue). Por defecto //! cae donde mira el plano de contraluz ([`SCENE_SUN`](crate::SCENE_SUN)), así //! que ese plano la encuadra. use llimphi_3d::glam::Vec3; use llimphi_3d::{Atmosphere, NightSky, PointLight}; use serde::{Deserialize, Serialize}; /// El cielo de una escena de noche. #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct Cielo { /// Color del cielo arriba. pub cenit: [u8; 3], /// Color del cielo en el horizonte; también el de la bruma. pub horizonte: [u8; 3], /// Cuántas estrellas, `0..1`. pub estrellas: f32, /// Dirección **hacia** la luna, sin normalizar. De ahí viene la luz. pub luna: [f32; 3], /// Radio de la luna en radianes; `0` = noche sin luna (la luz igual viene /// de esa dirección, pero no se dibuja el disco). pub luna_radio: f32, } impl Default for Cielo { fn default() -> Self { Self::noche() } } /// La luz que da una pieza de utilería con luz propia, de noche: alcance en /// metros (= voxels). pub const ALCANCE_LUZ_PROPIA: f32 = 7.0; impl Cielo { /// Una noche de cuento: azul profundo arriba, horizonte apenas más claro, /// muchas estrellas y una luna grande — se dibuja, no se fotografía. pub fn noche() -> Self { Self { cenit: [12, 18, 46], horizonte: [40, 50, 92], estrellas: 0.8, luna: crate::SCENE_SUN, luna_radio: 0.06, } } /// Lo que el renderer necesita para pintarla. pub fn night_sky(&self) -> NightSky { NightSky { amount: 1.0, stars: self.estrellas.clamp(0.0, 1.0), moon: self.luna_radio.max(0.0), } } /// La atmósfera de esta noche, con la bruma y los haces que ya traía quien /// filma (son del aire, no de la hora). pub fn atmosfera(&self, fog_density: f32, god_rays: f32) -> Atmosphere { Atmosphere { sky_zenith: self.cenit, sky_horizon: self.horizonte, fog_density, god_rays } } /// El color con que limpiar el cuadro antes de componer. pub fn fondo(&self) -> [u8; 4] { [self.horizonte[0], self.horizonte[1], self.horizonte[2], 255] } } /// La luz puntual que da una pieza con luz propia, centrada en ella. `centro` /// en coords de grilla; `color` el de la pieza (se normaliza al canal más alto: /// lo que alumbra es el tono, no el exceso que la marca como luminosa). pub fn luz_de(centro: Vec3, color: [f32; 3], alcance: f32) -> PointLight { let m = color[0].max(color[1]).max(color[2]).max(1e-3); PointLight { pos: centro.to_array(), color: [color[0] / m * 1.1, color[1] / m * 1.1, color[2] / m * 1.1], range: alcance, radius: 0.0, } }