Skip to main content

nightshade_api/
environment.rs

1//! Background, grid, fog, bloom, time of day, and other scene wide settings.
2
3use crate::runner::{SUN_NAME, lookup_named};
4use nightshade::prelude::*;
5use nightshade::render::config::DepthOfField;
6use serde::{Deserialize, Serialize};
7
8/// The tonemapping curve that maps HDR color to the display. `Aces` is the
9/// filmic default. `Reinhard`, `ReinhardExtended`, `Uncharted2`, `AgX`,
10/// `Neutral`, and `None` are the alternatives.
11pub use nightshade::render::config::TonemapAlgorithm as Tonemap;
12
13/// What fills the space behind your scene.
14#[derive(Clone, Debug, Serialize, Deserialize, enum2schema::Schema)]
15pub enum Background {
16    /// The procedural sky gradient. The default.
17    Sky,
18    /// The sky with volumetric clouds.
19    CloudySky,
20    /// A procedural starfield.
21    Space,
22    /// A procedural nebula with stars.
23    Nebula,
24    /// A procedural sunset gradient.
25    Sunset,
26    /// A solid color, linear RGBA.
27    Color([f32; 4]),
28    /// An equirectangular hdr image used as a skybox.
29    Hdr(Vec<u8>),
30}
31
32/// Sets the background. [`Background::Color`] switches the atmosphere off and
33/// sets the clear color together, which is the pairing the engine needs. The
34/// procedural skies recapture image based lighting automatically so
35/// reflective surfaces pick up the new sky.
36pub fn set_background(world: &mut World, background: Background) {
37    let settings = &mut world.res_mut::<nightshade::render::config::RenderSettings>();
38    match background {
39        Background::Sky => settings.atmosphere = Atmosphere::Sky,
40        Background::CloudySky => settings.atmosphere = Atmosphere::CloudySky,
41        Background::Space => settings.atmosphere = Atmosphere::Space,
42        Background::Nebula => settings.atmosphere = Atmosphere::Nebula,
43        Background::Sunset => settings.atmosphere = Atmosphere::Sunset,
44        Background::Color(color) => {
45            settings.atmosphere = Atmosphere::None;
46            settings.clear_color = color;
47        }
48        Background::Hdr(bytes) => {
49            load_hdr_skybox(world, bytes);
50        }
51    }
52}
53
54/// Shows or hides the reference grid. On by default.
55#[inline]
56pub fn show_grid(world: &mut World, enabled: bool) {
57    world
58        .res_mut::<nightshade::render::config::DebugDraw>()
59        .show_grid = enabled;
60}
61
62/// Sets the ambient light color, linear RGBA.
63#[inline]
64pub fn set_ambient(world: &mut World, color: [f32; 4]) {
65    world
66        .res_mut::<nightshade::render::config::RenderSettings>()
67        .ambient_light = color;
68}
69
70/// Sets the clear color the renderer uses for the clear pass, linear RGBA.
71#[inline]
72pub fn set_clear_color(world: &mut World, color: [f32; 4]) {
73    world
74        .res_mut::<nightshade::render::config::RenderSettings>()
75        .clear_color = color;
76}
77
78/// Enables distance fog between `Fog::start` and `Fog::end`, or disables it
79/// with `None`.
80#[inline]
81pub fn set_fog(world: &mut World, fog: Option<Fog>) {
82    world
83        .res_mut::<nightshade::render::config::RenderSettings>()
84        .fog = fog;
85}
86
87/// Toggles bloom. Emissive materials glow when this is on.
88#[inline]
89pub fn set_bloom(world: &mut World, enabled: bool) {
90    world
91        .res_mut::<nightshade::render::config::RenderSettings>()
92        .bloom_enabled = enabled;
93}
94
95/// Sets the bloom strength. The default is 0.5: lower keeps the glow subtle,
96/// higher blooms hard. Has no visible effect unless [`set_bloom`] is on.
97#[inline]
98pub fn set_bloom_intensity(world: &mut World, intensity: f32) {
99    world
100        .res_mut::<nightshade::render::config::RenderSettings>()
101        .bloom_intensity = intensity;
102}
103
104/// Sets the hour of the day from 0.0 to 24.0. Switches the sky to the day
105/// and night atmosphere and puts the default sun under its control, so the
106/// sun arcs and the light warms and cools with the hour. The hour you pass is
107/// authoritative, so call this every frame to animate time.
108pub fn set_time_of_day(world: &mut World, hour: f32) {
109    if world
110        .res::<nightshade::render::config::RendererState>()
111        .day_night
112        .sun_entity
113        .is_none()
114    {
115        world
116            .res_mut::<nightshade::render::config::RendererState>()
117            .day_night
118            .sun_entity = lookup_named(world, SUN_NAME).map(render_entity);
119    }
120    world
121        .res_mut::<nightshade::render::config::RenderSettings>()
122        .atmosphere = Atmosphere::DayNight;
123    world
124        .res_mut::<nightshade::render::config::RendererState>()
125        .day_night
126        .auto_cycle = true;
127    world
128        .res_mut::<nightshade::render::config::RendererState>()
129        .day_night
130        .speed = 0.0;
131    world
132        .res_mut::<nightshade::render::config::RendererState>()
133        .day_night
134        .hour = hour;
135}
136
137/// Sets the manual exposure multiplier. 1.0 is neutral, above brightens,
138/// below darkens.
139#[inline]
140pub fn set_exposure(world: &mut World, exposure: f32) {
141    world
142        .res_mut::<nightshade::render::config::RenderSettings>()
143        .color_grading
144        .exposure = exposure;
145}
146
147/// Sets depth of field. The engine ships presets: `DepthOfField::portrait()`,
148/// `cinematic()`, `macro_shot()`, `landscape()`, and `tilt_shift()`. Disable
149/// it by passing a default with `enabled` false.
150#[inline]
151pub fn set_depth_of_field(world: &mut World, depth_of_field: DepthOfField) {
152    world
153        .res_mut::<nightshade::render::config::RenderSettings>()
154        .depth_of_field = depth_of_field;
155}
156
157/// Toggles screen-space ambient occlusion, the contact shadowing that darkens
158/// creases and where objects meet.
159#[inline]
160pub fn set_ssao(world: &mut World, enabled: bool) {
161    world
162        .res_mut::<nightshade::render::config::RenderSettings>()
163        .ssao_enabled = enabled;
164}
165
166/// Toggles screen-space reflections on glossy surfaces.
167#[inline]
168pub fn set_ssr(world: &mut World, enabled: bool) {
169    world
170        .res_mut::<nightshade::render::config::RenderSettings>()
171        .ssr_enabled = enabled;
172}
173
174/// Toggles screen-space global illumination, one screen-space bounce of indirect
175/// light between surfaces.
176#[inline]
177pub fn set_ssgi(world: &mut World, enabled: bool) {
178    world
179        .res_mut::<nightshade::render::config::RenderSettings>()
180        .ssgi_enabled = enabled;
181}
182
183/// Toggles temporal antialiasing. Off by default.
184#[inline]
185pub fn set_taa(world: &mut World, enabled: bool) {
186    world
187        .res_mut::<nightshade::render::config::RenderSettings>()
188        .taa_enabled = enabled;
189}
190
191/// Sets the tonemapping curve that maps HDR to the display.
192#[inline]
193pub fn set_tonemap(world: &mut World, tonemap: Tonemap) {
194    world
195        .res_mut::<nightshade::render::config::RenderSettings>()
196        .color_grading
197        .tonemap_algorithm = tonemap;
198}
199
200/// Sets color grading. `saturation` and `contrast` are multipliers where 1.0 is
201/// neutral, `brightness` is an offset where 0.0 is neutral.
202#[inline]
203pub fn set_color_grading(world: &mut World, saturation: f32, contrast: f32, brightness: f32) {
204    let grading = &mut world
205        .res_mut::<nightshade::render::config::RenderSettings>()
206        .color_grading;
207    grading.saturation = saturation;
208    grading.contrast = contrast;
209    grading.brightness = brightness;
210}
211
212/// Saves a screenshot of the next rendered frame to `path` as a png.
213pub fn screenshot(world: &mut World, path: std::path::PathBuf) {
214    queue_render_command(
215        world,
216        RenderCommand::CaptureScreenshot {
217            path: Some(path),
218            max_dimension: None,
219        },
220    );
221}