fyrox_impl/scene/light/
directional.rs1use crate::{
30 core::{
31 algebra::{UnitQuaternion, Vector3},
32 color::Color,
33 math::aabb::AxisAlignedBoundingBox,
34 pool::Handle,
35 reflect::prelude::*,
36 type_traits::prelude::*,
37 uuid::{uuid, Uuid},
38 uuid_provider,
39 variable::InheritableVariable,
40 visitor::{Visit, VisitResult, Visitor},
41 },
42 scene::{
43 base::{Base, BaseBuilder},
44 debug::SceneDrawingContext,
45 graph::Graph,
46 light::{BaseLight, BaseLightBuilder},
47 node::constructor::NodeConstructor,
48 node::{Node, NodeTrait},
49 },
50};
51use fyrox_graph::constructor::ConstructorProvider;
52use fyrox_graph::BaseSceneGraph;
53use std::ops::{Deref, DerefMut};
54use strum_macros::{AsRefStr, EnumString, VariantNames};
55
56pub const CSM_NUM_CASCADES: usize = 3;
58
59#[derive(Reflect, Clone, Visit, Debug, PartialEq, AsRefStr, EnumString, VariantNames)]
61pub enum FrustumSplitOptions {
62 Absolute {
70 far_planes: [f32; CSM_NUM_CASCADES],
74 },
75 Relative {
80 fractions: [f32; CSM_NUM_CASCADES],
83 },
84}
85
86uuid_provider!(FrustumSplitOptions = "b2ed128a-b7da-4d34-b027-a0af19c2f563");
87
88impl Default for FrustumSplitOptions {
89 fn default() -> Self {
90 Self::Absolute {
91 far_planes: [5.0, 25.0, 64.0],
92 }
93 }
94}
95
96#[derive(Reflect, Clone, Visit, PartialEq, Debug)]
98pub struct CsmOptions {
99 pub split_options: FrustumSplitOptions,
101
102 #[reflect(min_value = 0.0, step = 0.000025)]
103 shadow_bias: f32,
104}
105
106impl Default for CsmOptions {
107 fn default() -> Self {
108 Self {
109 split_options: Default::default(),
110 shadow_bias: 0.00025,
111 }
112 }
113}
114
115impl CsmOptions {
116 pub fn set_shadow_bias(&mut self, bias: f32) {
120 self.shadow_bias = bias.max(0.0);
121 }
122
123 pub fn shadow_bias(&self) -> f32 {
125 self.shadow_bias
126 }
127}
128
129#[derive(Default, Debug, Visit, Reflect, Clone, ComponentProvider)]
131pub struct DirectionalLight {
132 #[component(include)]
133 base_light: BaseLight,
134 pub csm_options: InheritableVariable<CsmOptions>,
136}
137
138impl From<BaseLight> for DirectionalLight {
139 fn from(base_light: BaseLight) -> Self {
140 Self {
141 base_light,
142 csm_options: Default::default(),
143 }
144 }
145}
146
147impl Deref for DirectionalLight {
148 type Target = Base;
149
150 fn deref(&self) -> &Self::Target {
151 &self.base_light.base
152 }
153}
154
155impl DerefMut for DirectionalLight {
156 fn deref_mut(&mut self) -> &mut Self::Target {
157 &mut self.base_light.base
158 }
159}
160
161impl TypeUuidProvider for DirectionalLight {
162 fn type_uuid() -> Uuid {
163 uuid!("8b8248e1-1cdf-42a3-9abe-0691de82c519")
164 }
165}
166
167impl DirectionalLight {
168 pub fn base_light_ref(&self) -> &BaseLight {
170 &self.base_light
171 }
172
173 pub fn base_light_mut(&mut self) -> &mut BaseLight {
175 &mut self.base_light
176 }
177}
178
179impl ConstructorProvider<Node, Graph> for DirectionalLight {
180 fn constructor() -> NodeConstructor {
181 NodeConstructor::new::<Self>()
182 .with_variant("Directional Light", |_| {
183 DirectionalLightBuilder::new(BaseLightBuilder::new(
184 BaseBuilder::new().with_name("DirectionalLight"),
185 ))
186 .build_node()
187 .into()
188 })
189 .with_group("Light")
190 }
191}
192
193impl NodeTrait for DirectionalLight {
194 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
195 AxisAlignedBoundingBox::default()
196 }
197
198 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
199 self.local_bounding_box()
200 .transform(&self.global_transform())
201 }
202
203 fn id(&self) -> Uuid {
204 Self::type_uuid()
205 }
206
207 fn debug_draw(&self, ctx: &mut SceneDrawingContext) {
208 ctx.draw_arrow(
209 16,
210 Color::GREEN,
211 1.0,
212 0.2,
213 self.global_transform()
214 * UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 180.0f32.to_radians())
215 .to_homogeneous(),
216 );
217 }
218}
219
220pub struct DirectionalLightBuilder {
222 base_light_builder: BaseLightBuilder,
223 csm_options: CsmOptions,
224}
225
226impl DirectionalLightBuilder {
227 pub fn new(base_light_builder: BaseLightBuilder) -> Self {
229 Self {
230 base_light_builder,
231 csm_options: Default::default(),
232 }
233 }
234
235 pub fn build_directional_light(self) -> DirectionalLight {
237 DirectionalLight {
238 base_light: self.base_light_builder.build(),
239 csm_options: self.csm_options.into(),
240 }
241 }
242
243 pub fn with_csm_options(mut self, csm_options: CsmOptions) -> Self {
245 self.csm_options = csm_options;
246 self
247 }
248
249 pub fn build_node(self) -> Node {
251 Node::new(self.build_directional_light())
252 }
253
254 pub fn build(self, graph: &mut Graph) -> Handle<Node> {
256 graph.add_node(self.build_node())
257 }
258}