rustic_zen/scene/light.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use crate::sampler::{Sampler, SamplerPoint};
6use rand::prelude::*;
7
8/// Definition of a Light Source in for a scene.
9///
10/// # Examples
11/// Manually make a warm white small round light:
12/// ```
13/// use rustic_zen::prelude::*;
14///
15/// let l = Light {
16/// power: Sampler::new_const(1.0),
17/// location: (512.0, 512.0).into(),
18/// polar_angle: Sampler::new_const(0.0),
19/// polar_distance: Sampler::new_const(0.0),
20/// ray_angle: Sampler::new_range(360.0, 0.0),
21/// wavelength: Sampler::new_blackbody(5800.0),
22/// };
23///
24/// let scene = Scene::new(1920,1080).with_light(l);
25/// ```
26#[derive(Clone)]
27pub struct Light<R: Rng> {
28 /// coordinates of the light in the scene.
29 pub location: SamplerPoint<R>,
30 /// Brightness of this light relative to other lights in the scene. This is a proportion of the total
31 /// power of all lights of the scene. So if you have 50 lights of power 1 each light has a 1 in 50
32 /// chance of being selected to spawn a ray. However adding 1 more light with power 10 will lower the
33 /// existing lights to 1 in 60 and the new light will have 1 in 6. once used this is quite intuitive,
34 /// the power will change the relative brightness of the lights, without changing the overall brightness
35 /// of the scene.
36 pub power: Sampler<f64, R>,
37 /// distance from `location` that the light ray will spawn,
38 /// this can be used to create lights that are larger than a single pixel
39 /// Fixing this to a single value will create a ring where the rays spawn,
40 /// using a range of 0 - `size` will create a filled circle of spawn points.
41 pub polar_distance: Sampler<f64, R>,
42 /// combined with `polar_distance` this creates a vector that is added to `location`
43 /// to generate the final point the light ray will spawn. Using a range of 360 - 0
44 /// will create a full circle, constraining this can create an arc.
45 pub polar_angle: Sampler<f64, R>,
46 /// Angle at which the spawned ray will fly away from the light. This is in absolute
47 /// screen angle (0 is right). Setting this to a range of 0 - 360 will create an omidirectional
48 /// light, constraining this range creates a more cone like light. Constraining it all
49 /// the way to a single fixed value will create a laser. Using a `polar_distance` > 0 is
50 /// recomended if the `ray_angle` is constrained to a single value, as a ray 1 pixel wide can be
51 /// hard to see.
52 pub ray_angle: Sampler<f64, R>,
53 /// Wavelength of spawned ray in nanometers. Only values of 380.0 - 700.0 are visible.
54 /// Using a fixed value will create a strongly coloured light of that wavelength. To create natural
55 /// looking white lights use `Sampler::new_blackbody(<temp>)`. Blackbody tempratures of 1,000 to
56 /// 10,000 kelvin are visible.
57 ///
58 /// # Warning
59 /// __Rays are sampled until a visible wavelength is found, this is an optimisation, selecting a fixed value
60 /// or range of values outside of the visible spectrum can crash the render. So can selecting extreme
61 /// blackbody tempratures.__
62 pub wavelength: Sampler<f64, R>,
63}
64
65impl<R> Light<R>
66where
67 R: Rng,
68{
69 /// Helper function to create a Light quickly, using common casts
70 /// available in the library.
71 ///
72 /// # Example Usage
73 /// Create the same small round light as above using the helper:
74 /// ```
75 /// use rustic_zen::prelude::*;
76 ///
77 /// let l = Light::new((512.0,512.0), 1.0, 0.0, 0.0, (360.0, 0.0), Sampler::new_blackbody(5800.0));
78 ///
79 /// let scene = Scene::new(1920,1080).with_light(l);
80 /// ```
81 pub fn new<A, B, C, D, E, F>(
82 location: A,
83 power: B,
84 polar_distance: C,
85 polar_angle: D,
86 ray_angle: E,
87 wavelength: F,
88 ) -> Self
89 where
90 A: Into<SamplerPoint<R>>,
91 B: Into<Sampler<f64, R>>,
92 C: Into<Sampler<f64, R>>,
93 D: Into<Sampler<f64, R>>,
94 E: Into<Sampler<f64, R>>,
95 F: Into<Sampler<f64, R>>,
96 {
97 Self {
98 location: location.into(),
99 power: power.into(),
100 polar_distance: polar_distance.into(),
101 polar_angle: polar_angle.into(),
102 ray_angle: ray_angle.into(),
103 wavelength: wavelength.into(),
104 }
105 }
106}