Skip to main content

wde_pbr/deferred/lights/
lights_types.rs

1use wde_renderer::prelude::Color;
2
3use bevy::prelude::*;
4
5/// Default values for the lights.
6const DEFAULT_INTENSITY: f32 = 1.0;
7const INTENSITY_MULTIPLIER: f32 = 10.0; // To convert from "standard" intensity to lumens
8
9/// A directional light is a light that emits light in a single direction from an infinite distance.
10#[derive(Component, Clone, Copy, Reflect)]
11#[reflect(Component)]
12pub struct DirectionalLight {
13    /// World space direction of the light.
14    pub direction: Vec3,
15
16    /// Light color (RGB).
17    pub color: Color,
18    /// Light intensity/brightness (in lumens, physical-based).
19    pub intensity: f32
20}
21impl Default for DirectionalLight {
22    fn default() -> Self {
23        Self {
24            direction: Vec3::new(0.0, -1.0, 0.0),
25            color: Color::from_srgba(1.0, 1.0, 1.0, 1.0),
26            intensity: DEFAULT_INTENSITY * INTENSITY_MULTIPLIER
27        }
28    }
29}
30
31/// A point light is a light that emits light in all directions from a single point.
32#[derive(Component, Clone, Copy, Reflect)]
33#[reflect(Component)]
34pub struct PointLight {
35    /// Position of the light: relative to its entity when it has a transform, else in world space.
36    pub position: Vec3,
37
38    /// Light color (RGB).
39    pub color: Color,
40    /// Light intensity/brightness (in lumens, physical-based).
41    pub intensity: f32,
42    /// Maximum range of light influence (in world units).
43    pub range: f32
44}
45impl Default for PointLight {
46    fn default() -> Self {
47        Self {
48            position: Vec3::new(0.0, 0.0, 0.0),
49            color: Color::from_srgba(1.0, 1.0, 1.0, 1.0),
50            intensity: DEFAULT_INTENSITY * INTENSITY_MULTIPLIER,
51            range: 100.0
52        }
53    }
54}
55
56/// A spotlight is a point light with a direction and cone angles.
57#[derive(Component, Clone, Copy, Reflect)]
58#[reflect(Component)]
59pub struct SpotLight {
60    /// Position of the light: relative to its entity when it has a transform, else in world space.
61    pub position: Vec3,
62    /// Direction of the light: relative to its entity when it has a transform, else in world space.
63    pub direction: Vec3,
64
65    /// Light color (RGB).
66    pub color: Color,
67    /// Light intensity/brightness (in lumens, physical-based).
68    pub intensity: f32,
69    /// Maximum range of light influence (in world units).
70    pub range: f32,
71
72    /// Inner cone angle of the light (in radians): full brightness cone.
73    pub inner_cone: f32,
74    /// Outer cone angle of the light (in radians): edge of cone with smooth falloff.
75    pub outer_cone: f32
76}
77impl Default for SpotLight {
78    fn default() -> Self {
79        Self {
80            position: Vec3::new(0.0, 0.0, 0.0),
81            direction: Vec3::new(0.0, -1.0, 0.0),
82            color: Color::from_srgba(1.0, 1.0, 1.0, 1.0),
83            intensity: DEFAULT_INTENSITY * INTENSITY_MULTIPLIER,
84            range: 50.0,
85            inner_cone: std::f32::consts::PI / 12.0, // 15 degrees
86            outer_cone: std::f32::consts::PI / 6.0   // 30 degrees
87        }
88    }
89}
90
91/// Lights storage buffer (matches the shader Light struct)
92#[repr(C)]
93#[derive(Resource, Default, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
94pub(crate) struct LightsStorageElement {
95    /// (x, y, z) = World space position of the light - w = Light intensity (brightness in lumens)
96    pub position_intensity: [f32; 4],
97    /// (x, y, z) = Light color - w = Light type (0 = directional, 1 = point, 2 = spot)
98    pub color_type: [f32; 4],
99    /// (x, y, z) = Direction of the light - w = Light range (max influence distance)
100    pub direction_range: [f32; 4],
101    /// Spot light inner and outer cone angles (cos values). Only used for spot lights.
102    pub spot_cone: [f32; 4]
103}
104impl LightsStorageElement {
105    /// Marks the end of the lights in use.
106    pub fn end_marker() -> Self {
107        Self {
108            color_type: [0.0, 0.0, 0.0, -1.0],
109            ..Default::default()
110        }
111    }
112
113    pub fn from_directional(light: &DirectionalLight) -> Self {
114        let color = light.color.to_linear_rgba();
115        Self {
116            position_intensity: [0.0, 0.0, 0.0, light.intensity * INTENSITY_MULTIPLIER],
117            color_type: [color.r(), color.g(), color.b(), 0.0],
118            direction_range: [light.direction.x, light.direction.y, light.direction.z, 0.0],
119            spot_cone: [0.0, 0.0, 0.0, 0.0]
120        }
121    }
122
123    pub fn from_point(light: &PointLight) -> Self {
124        let color = light.color.to_linear_rgba();
125        Self {
126            position_intensity: [
127                light.position.x,
128                light.position.y,
129                light.position.z,
130                light.intensity * INTENSITY_MULTIPLIER
131            ],
132            color_type: [color.r(), color.g(), color.b(), 1.0],
133            direction_range: [0.0, 0.0, 0.0, light.range],
134            spot_cone: [0.0, 0.0, 0.0, 0.0]
135        }
136    }
137
138    pub fn from_spot(light: &SpotLight) -> Self {
139        let color = light.color.to_linear_rgba();
140        Self {
141            position_intensity: [
142                light.position.x,
143                light.position.y,
144                light.position.z,
145                light.intensity * INTENSITY_MULTIPLIER
146            ],
147            color_type: [color.r(), color.g(), color.b(), 2.0],
148            direction_range: [
149                light.direction.x,
150                light.direction.y,
151                light.direction.z,
152                light.range
153            ],
154            spot_cone: [light.inner_cone.cos(), light.outer_cone.cos(), 0.0, 0.0]
155        }
156    }
157}