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::SceneGraph;
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)]
131#[reflect(derived_type = "Node")]
132pub struct DirectionalLight {
133 #[component(include)]
134 base_light: BaseLight,
135 pub csm_options: InheritableVariable<CsmOptions>,
137}
138
139impl From<BaseLight> for DirectionalLight {
140 fn from(base_light: BaseLight) -> Self {
141 Self {
142 base_light,
143 csm_options: Default::default(),
144 }
145 }
146}
147
148impl Deref for DirectionalLight {
149 type Target = Base;
150
151 fn deref(&self) -> &Self::Target {
152 &self.base_light.base
153 }
154}
155
156impl DerefMut for DirectionalLight {
157 fn deref_mut(&mut self) -> &mut Self::Target {
158 &mut self.base_light.base
159 }
160}
161
162impl TypeUuidProvider for DirectionalLight {
163 fn type_uuid() -> Uuid {
164 uuid!("8b8248e1-1cdf-42a3-9abe-0691de82c519")
165 }
166}
167
168impl DirectionalLight {
169 pub fn base_light_ref(&self) -> &BaseLight {
171 &self.base_light
172 }
173
174 pub fn base_light_mut(&mut self) -> &mut BaseLight {
176 &mut self.base_light
177 }
178}
179
180impl ConstructorProvider<Node, Graph> for DirectionalLight {
181 fn constructor() -> NodeConstructor {
182 NodeConstructor::new::<Self>()
183 .with_variant("Directional Light", |_| {
184 DirectionalLightBuilder::new(BaseLightBuilder::new(
185 BaseBuilder::new().with_name("DirectionalLight"),
186 ))
187 .build_node()
188 .into()
189 })
190 .with_group("Light")
191 }
192}
193
194impl NodeTrait for DirectionalLight {
195 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
196 AxisAlignedBoundingBox::default()
197 }
198
199 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
200 self.local_bounding_box()
201 .transform(&self.global_transform())
202 }
203
204 fn id(&self) -> Uuid {
205 Self::type_uuid()
206 }
207
208 fn debug_draw(&self, ctx: &mut SceneDrawingContext) {
209 ctx.draw_arrow(
210 16,
211 Color::GREEN,
212 1.0,
213 0.2,
214 self.global_transform()
215 * UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 180.0f32.to_radians())
216 .to_homogeneous(),
217 );
218 }
219}
220
221pub struct DirectionalLightBuilder {
223 base_light_builder: BaseLightBuilder,
224 csm_options: CsmOptions,
225}
226
227impl DirectionalLightBuilder {
228 pub fn new(base_light_builder: BaseLightBuilder) -> Self {
230 Self {
231 base_light_builder,
232 csm_options: Default::default(),
233 }
234 }
235
236 pub fn build_directional_light(self) -> DirectionalLight {
238 DirectionalLight {
239 base_light: self.base_light_builder.build(),
240 csm_options: self.csm_options.into(),
241 }
242 }
243
244 pub fn with_csm_options(mut self, csm_options: CsmOptions) -> Self {
246 self.csm_options = csm_options;
247 self
248 }
249
250 pub fn build_node(self) -> Node {
252 Node::new(self.build_directional_light())
253 }
254
255 pub fn build(self, graph: &mut Graph) -> Handle<DirectionalLight> {
257 graph.add_node(self.build_node()).to_variant()
258 }
259}