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    /// World space position of the light.
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    /// World space position of the light.
61    pub position: Vec3,
62    /// World space direction of the light.
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    pub fn from_directional(light: &DirectionalLight) -> Self {
106        let color = light.color.to_linear_rgba();
107        Self {
108            position_intensity: [0.0, 0.0, 0.0, light.intensity * INTENSITY_MULTIPLIER],
109            color_type: [color.r(), color.g(), color.b(), 0.0],
110            direction_range: [light.direction.x, light.direction.y, light.direction.z, 0.0],
111            spot_cone: [0.0, 0.0, 0.0, 0.0]
112        }
113    }
114
115    pub fn from_point(light: &PointLight) -> Self {
116        let color = light.color.to_linear_rgba();
117        Self {
118            position_intensity: [
119                light.position.x,
120                light.position.y,
121                light.position.z,
122                light.intensity * INTENSITY_MULTIPLIER
123            ],
124            color_type: [color.r(), color.g(), color.b(), 1.0],
125            direction_range: [0.0, 0.0, 0.0, light.range],
126            spot_cone: [0.0, 0.0, 0.0, 0.0]
127        }
128    }
129
130    pub fn from_spot(light: &SpotLight) -> Self {
131        let color = light.color.to_linear_rgba();
132        Self {
133            position_intensity: [
134                light.position.x,
135                light.position.y,
136                light.position.z,
137                light.intensity * INTENSITY_MULTIPLIER
138            ],
139            color_type: [color.r(), color.g(), color.b(), 2.0],
140            direction_range: [
141                light.direction.x,
142                light.direction.y,
143                light.direction.z,
144                light.range
145            ],
146            spot_cone: [light.inner_cone.cos(), light.outer_cone.cos(), 0.0, 0.0]
147        }
148    }
149}