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::ecs::graphics::resources::DepthOfField;
5use nightshade::prelude::*;
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::ecs::graphics::resources::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 also recapture image based lighting so reflective
35/// surfaces pick up the new sky.
36pub fn set_background(world: &mut World, background: Background) {
37    match background {
38        Background::Sky => set_atmosphere(world, Atmosphere::Sky),
39        Background::CloudySky => set_atmosphere(world, Atmosphere::CloudySky),
40        Background::Space => set_atmosphere(world, Atmosphere::Space),
41        Background::Nebula => set_atmosphere(world, Atmosphere::Nebula),
42        Background::Sunset => set_atmosphere(world, Atmosphere::Sunset),
43        Background::Color(color) => {
44            world.resources.render_settings.atmosphere = Atmosphere::None;
45            world.resources.render_settings.clear_color = color;
46        }
47        Background::Hdr(bytes) => {
48            load_hdr_skybox(world, bytes);
49        }
50    }
51}
52
53fn set_atmosphere(world: &mut World, atmosphere: Atmosphere) {
54    world.resources.render_settings.atmosphere = atmosphere;
55    capture_procedural_atmosphere_ibl(world, atmosphere, 0.0);
56}
57
58/// Shows or hides the reference grid. On by default.
59#[inline]
60pub fn show_grid(world: &mut World, enabled: bool) {
61    world.resources.debug_draw.show_grid = enabled;
62}
63
64/// Sets the ambient light color, linear RGBA.
65#[inline]
66pub fn set_ambient(world: &mut World, color: [f32; 4]) {
67    world.resources.render_settings.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.resources.render_settings.clear_color = color;
74}
75
76/// Enables distance fog between `Fog::start` and `Fog::end`, or disables it
77/// with `None`.
78#[inline]
79pub fn set_fog(world: &mut World, fog: Option<Fog>) {
80    world.resources.render_settings.fog = fog;
81}
82
83/// Toggles bloom. Emissive materials glow when this is on.
84#[inline]
85pub fn set_bloom(world: &mut World, enabled: bool) {
86    world.resources.render_settings.bloom_enabled = enabled;
87}
88
89/// Sets the bloom strength. The default is 0.5: lower keeps the glow subtle,
90/// higher blooms hard. Has no visible effect unless [`set_bloom`] is on.
91#[inline]
92pub fn set_bloom_intensity(world: &mut World, intensity: f32) {
93    world.resources.render_settings.bloom_intensity = intensity;
94}
95
96/// Sets the hour of the day from 0.0 to 24.0. Switches the sky to the day
97/// and night atmosphere and puts the default sun under its control, so the
98/// sun arcs and the light warms and cools with the hour. The hour you pass is
99/// authoritative, so call this every frame to animate time.
100pub fn set_time_of_day(world: &mut World, hour: f32) {
101    if world
102        .resources
103        .renderer_state
104        .day_night
105        .sun_entity
106        .is_none()
107    {
108        world.resources.renderer_state.day_night.sun_entity = lookup_named(world, SUN_NAME);
109    }
110    world.resources.render_settings.atmosphere = Atmosphere::DayNight;
111    world.resources.renderer_state.day_night.auto_cycle = true;
112    world.resources.renderer_state.day_night.speed = 0.0;
113    world.resources.renderer_state.day_night.hour = hour;
114}
115
116/// Sets the manual exposure multiplier. 1.0 is neutral, above brightens,
117/// below darkens.
118#[inline]
119pub fn set_exposure(world: &mut World, exposure: f32) {
120    world.resources.render_settings.color_grading.exposure = exposure;
121}
122
123/// Sets depth of field. The engine ships presets: `DepthOfField::portrait()`,
124/// `cinematic()`, `macro_shot()`, `landscape()`, and `tilt_shift()`. Disable
125/// it by passing a default with `enabled` false.
126#[inline]
127pub fn set_depth_of_field(world: &mut World, depth_of_field: DepthOfField) {
128    world.resources.render_settings.depth_of_field = depth_of_field;
129}
130
131/// Toggles screen-space ambient occlusion, the contact shadowing that darkens
132/// creases and where objects meet.
133#[inline]
134pub fn set_ssao(world: &mut World, enabled: bool) {
135    world.resources.render_settings.ssao_enabled = enabled;
136}
137
138/// Toggles screen-space reflections on glossy surfaces.
139#[inline]
140pub fn set_ssr(world: &mut World, enabled: bool) {
141    world.resources.render_settings.ssr_enabled = enabled;
142}
143
144/// Toggles screen-space global illumination, one screen-space bounce of indirect
145/// light between surfaces.
146#[inline]
147pub fn set_ssgi(world: &mut World, enabled: bool) {
148    world.resources.render_settings.ssgi_enabled = enabled;
149}
150
151/// Toggles temporal antialiasing. On by default.
152#[inline]
153pub fn set_taa(world: &mut World, enabled: bool) {
154    world.resources.render_settings.taa_enabled = enabled;
155}
156
157/// Sets the tonemapping curve that maps HDR to the display.
158#[inline]
159pub fn set_tonemap(world: &mut World, tonemap: Tonemap) {
160    world
161        .resources
162        .render_settings
163        .color_grading
164        .tonemap_algorithm = tonemap;
165}
166
167/// Sets color grading. `saturation` and `contrast` are multipliers where 1.0 is
168/// neutral, `brightness` is an offset where 0.0 is neutral.
169#[inline]
170pub fn set_color_grading(world: &mut World, saturation: f32, contrast: f32, brightness: f32) {
171    let grading = &mut world.resources.render_settings.color_grading;
172    grading.saturation = saturation;
173    grading.contrast = contrast;
174    grading.brightness = brightness;
175}
176
177/// Saves a screenshot of the next rendered frame to `path` as a png.
178pub fn screenshot(world: &mut World, path: std::path::PathBuf) {
179    queue_render_command(
180        world,
181        RenderCommand::CaptureScreenshot {
182            path: Some(path),
183            max_dimension: None,
184        },
185    );
186}