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}