fyrox_impl/scene/light/
mod.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Contains all structures and methods to create and manage lights.
22//!
23//! Light sources arte basic building blocks of many scenes in games, it improves
24//! perception of scene and makes it look natural. Fyrox engine supports three kinds
25//! of light sources:
26//!
27//! 1) Directional - similar to sun in real life, its rays are parallel.
28//! 2) Spot - similar to flash light, it has cone light volume and circle spot.
29//! 3) Point - similar to light bulb, it has spherical light volume.
30//!
31//! Each kind of light source is suitable for specific conditions, for example
32//! spot light can be used if you have a character with flashlight, point - if
33//! you have a character with torch, and finally directional - for outdoor light.
34//!
35//! Most of light sources supports shadows (via shadows maps) and light scattering,
36//! these are common effects for modern games but still can significantly impact
37//! performance.
38
39use crate::{
40    core::{
41        algebra::Vector3,
42        color::Color,
43        reflect::prelude::*,
44        variable::InheritableVariable,
45        visitor::{Visit, VisitResult, Visitor},
46    },
47    scene::base::{Base, BaseBuilder},
48};
49use std::ops::{Deref, DerefMut};
50
51pub mod directional;
52pub mod point;
53pub mod spot;
54
55/// Default amount of light scattering, it is set to 3% which is fairly
56/// significant value and you'll clearly see light volume with such settings.
57pub const DEFAULT_SCATTER_R: f32 = 0.03;
58
59/// Default amount of light scattering, it is set to 3% which is fairly
60/// significant value and you'll clearly see light volume with such settings.
61pub const DEFAULT_SCATTER_G: f32 = 0.03;
62
63/// Default amount of light scattering, it is set to 3% which is fairly
64/// significant value and you'll clearly see light volume with such settings.
65pub const DEFAULT_SCATTER_B: f32 = 0.03;
66
67/// Light scene node. It contains common properties of light such as color,
68/// scattering factor (per color channel) and other useful properties. Exact
69/// behavior defined by specific light kind.
70#[derive(Debug, Reflect, Clone, Visit)]
71pub struct BaseLight {
72    base: Base,
73
74    #[reflect(setter = "set_color")]
75    color: InheritableVariable<Color>,
76
77    #[visit(rename = "ScatterFactor")]
78    #[reflect(setter = "set_scatter")]
79    scatter: InheritableVariable<Vector3<f32>>,
80
81    #[reflect(setter = "enable_scatter")]
82    scatter_enabled: InheritableVariable<bool>,
83
84    #[reflect(min_value = 0.0, step = 0.1)]
85    #[reflect(setter = "set_intensity")]
86    intensity: InheritableVariable<f32>,
87}
88
89impl Deref for BaseLight {
90    type Target = Base;
91
92    fn deref(&self) -> &Self::Target {
93        &self.base
94    }
95}
96
97impl DerefMut for BaseLight {
98    fn deref_mut(&mut self) -> &mut Self::Target {
99        &mut self.base
100    }
101}
102
103impl Default for BaseLight {
104    fn default() -> Self {
105        Self {
106            base: Default::default(),
107            color: InheritableVariable::new_modified(Color::WHITE),
108            scatter: InheritableVariable::new_modified(Vector3::new(
109                DEFAULT_SCATTER_R,
110                DEFAULT_SCATTER_G,
111                DEFAULT_SCATTER_B,
112            )),
113            scatter_enabled: InheritableVariable::new_modified(true),
114            intensity: InheritableVariable::new_modified(1.0),
115        }
116    }
117}
118
119impl BaseLight {
120    /// Sets color of light, alpha component of color is ignored.
121    #[inline]
122    pub fn set_color(&mut self, color: Color) -> Color {
123        self.color.set_value_and_mark_modified(color)
124    }
125
126    /// Returns current color of light source.
127    #[inline]
128    pub fn color(&self) -> Color {
129        *self.color
130    }
131
132    /// Sets scatter factor per color channel (red, green, blue) in (0..1) range.
133    /// This parameter defines how "thick" environment is and how much light will
134    /// be scattered in light volume. Ability to change this parameter per channel
135    /// allows you simulate Rayleigh scatter if needed - in simple words Rayleigh
136    /// scatter tells us that blue light waves scatters much better than red ones,
137    /// this effect makes sky blue. Reasonable value is something near 0.024-0.03
138    /// per color channel, higher values will cause too "heavy" light scattering
139    /// as if you light source would be in fog.
140    #[inline]
141    pub fn set_scatter(&mut self, f: Vector3<f32>) -> Vector3<f32> {
142        self.scatter.set_value_and_mark_modified(f)
143    }
144
145    /// Returns current scatter factor.
146    #[inline]
147    pub fn scatter(&self) -> Vector3<f32> {
148        *self.scatter
149    }
150
151    /// Sets new light intensity. Default is 1.0.
152    ///
153    /// Intensity is used for very bright light sources in HDR. For examples, sun
154    /// can be represented as directional light source with very high intensity.
155    /// Other lights, however, will remain relatively dim.
156    pub fn set_intensity(&mut self, intensity: f32) -> f32 {
157        self.intensity.set_value_and_mark_modified(intensity)
158    }
159
160    /// Returns current intensity of the light.
161    pub fn intensity(&self) -> f32 {
162        *self.intensity
163    }
164
165    /// Returns current scatter factor in linear color space.
166    #[inline]
167    pub fn scatter_linear(&self) -> Vector3<f32> {
168        self.scatter.map(|v| v.powf(2.2))
169    }
170
171    /// Enables or disables light scattering.
172    #[inline]
173    pub fn enable_scatter(&mut self, state: bool) -> bool {
174        self.scatter_enabled.set_value_and_mark_modified(state)
175    }
176
177    /// Returns true if light scattering is enabled, false - otherwise.
178    #[inline]
179    pub fn is_scatter_enabled(&self) -> bool {
180        *self.scatter_enabled
181    }
182}
183
184/// Light scene node builder. Provides easy declarative way of creating light scene
185/// nodes.
186pub struct BaseLightBuilder {
187    base_builder: BaseBuilder,
188    color: Color,
189    scatter_factor: Vector3<f32>,
190    scatter_enabled: bool,
191    intensity: f32,
192}
193
194impl BaseLightBuilder {
195    /// Creates new instance of light scene node builder, you must pass desired
196    /// light kind and base scene node builder as parameters. Latter one is needed
197    /// because engine uses composition and light scene node built on top of base
198    /// scene node.
199    pub fn new(base_builder: BaseBuilder) -> Self {
200        Self {
201            base_builder,
202            color: Color::WHITE,
203            scatter_factor: Vector3::new(DEFAULT_SCATTER_R, DEFAULT_SCATTER_G, DEFAULT_SCATTER_B),
204            scatter_enabled: true,
205            intensity: 1.0,
206        }
207    }
208
209    /// Sets light color.
210    pub fn with_color(mut self, color: Color) -> Self {
211        self.color = color;
212        self
213    }
214
215    /// Sets light scatter factor per color channel.
216    pub fn with_scatter_factor(mut self, f: Vector3<f32>) -> Self {
217        self.scatter_factor = f;
218        self
219    }
220
221    /// Whether light scatter enabled or not.
222    pub fn with_scatter_enabled(mut self, state: bool) -> Self {
223        self.scatter_enabled = state;
224        self
225    }
226
227    /// Sets desired light intensity.
228    pub fn with_intensity(mut self, intensity: f32) -> Self {
229        self.intensity = intensity;
230        self
231    }
232
233    /// Creates new instance of base light.
234    pub fn build(self) -> BaseLight {
235        BaseLight {
236            base: self.base_builder.build_base(),
237            color: self.color.into(),
238            scatter: self.scatter_factor.into(),
239            scatter_enabled: self.scatter_enabled.into(),
240            intensity: self.intensity.into(),
241        }
242    }
243}