1use glium::{Display, Texture2d};
2use glium::framebuffer::DepthRenderBuffer;
3use glium::glutin::surface::WindowSurface;
4use glium::texture::RawImage2d;
5
6pub struct ShadowMaps {
7 pub directional_maps: [Option<Texture2d>; 4],
8 pub point_maps: [Option<Texture2d>; 4],
9 pub light_space_matrices: [[[f32; 4]; 4]; 4],
10 pub point_far_planes: [f32; 4],
11 pub resolution: u32,
12 pub dir_depth_rb: DepthRenderBuffer,
13 pub point_depth_rb: DepthRenderBuffer,
14 pub dummy: Texture2d,
15}
16
17const IDENTITY: [[f32; 4]; 4] = [
18 [1.0, 0.0, 0.0, 0.0],
19 [0.0, 1.0, 0.0, 0.0],
20 [0.0, 0.0, 1.0, 0.0],
21 [0.0, 0.0, 0.0, 1.0],
22];
23
24impl ShadowMaps {
25 pub fn new(display: &Display<WindowSurface>, resolution: u32) -> Self {
26 let dir_depth_rb = DepthRenderBuffer::new(
27 display,
28 glium::texture::DepthFormat::F32,
29 resolution,
30 resolution,
31 ).expect("Failed to create directional shadow depth renderbuffer");
32
33 let point_depth_rb = DepthRenderBuffer::new(
34 display,
35 glium::texture::DepthFormat::F32,
36 resolution * 2,
37 resolution * 3,
38 ).expect("Failed to create point shadow depth renderbuffer");
39
40 let dummy = Texture2d::new(
41 display,
42 RawImage2d::from_raw_rgba_reversed(&[255u8, 0, 0, 255], (1, 1)),
43 ).expect("Failed to create dummy shadow texture");
44
45 Self {
46 directional_maps: [None, None, None, None],
47 point_maps: [None, None, None, None],
48 light_space_matrices: [IDENTITY; 4],
49 point_far_planes: [100.0; 4],
50 resolution,
51 dir_depth_rb,
52 point_depth_rb,
53 dummy,
54 }
55 }
56
57 pub fn clear(&mut self) {
58 for i in 0..4 {
59 self.directional_maps[i] = None;
60 self.point_maps[i] = None;
61 }
62 }
63}
64
65pub fn view_matrix(position: &[f32; 3], direction: &[f32; 3], up: &[f32; 3]) -> [[f32; 4]; 4] {
68 let len = (direction[0]*direction[0] + direction[1]*direction[1] + direction[2]*direction[2]).sqrt();
69 let f = [-direction[0]/len, -direction[1]/len, -direction[2]/len];
70
71 let s = [
72 up[1]*f[2] - up[2]*f[1],
73 up[2]*f[0] - up[0]*f[2],
74 up[0]*f[1] - up[1]*f[0],
75 ];
76 let s_len = (s[0]*s[0] + s[1]*s[1] + s[2]*s[2]).sqrt();
77 let s = [s[0]/s_len, s[1]/s_len, s[2]/s_len];
78
79 let u = [
80 f[1]*s[2] - f[2]*s[1],
81 f[2]*s[0] - f[0]*s[2],
82 f[0]*s[1] - f[1]*s[0],
83 ];
84
85 let p = [
86 -position[0]*s[0] - position[1]*s[1] - position[2]*s[2],
87 -position[0]*u[0] - position[1]*u[1] - position[2]*u[2],
88 -position[0]*f[0] - position[1]*f[1] - position[2]*f[2],
89 ];
90
91 [
92 [s[0], u[0], f[0], 0.0],
93 [s[1], u[1], f[1], 0.0],
94 [s[2], u[2], f[2], 0.0],
95 [p[0], p[1], p[2], 1.0],
96 ]
97}
98
99pub fn ortho_matrix(l: f32, r: f32, b: f32, t: f32, near: f32, far: f32) -> [[f32; 4]; 4] {
100 [
101 [2.0/(r-l), 0.0, 0.0, 0.0],
102 [0.0, 2.0/(t-b), 0.0, 0.0],
103 [0.0, 0.0, -2.0/(far-near), 0.0],
104 [-(r+l)/(r-l), -(t+b)/(t-b), -(far+near)/(far-near), 1.0],
105 ]
106}
107
108pub fn perspective_90_matrix(near: f32, far: f32) -> [[f32; 4]; 4] {
109 [
111 [1.0, 0.0, 0.0, 0.0],
112 [0.0, 1.0, 0.0, 0.0],
113 [0.0, 0.0, (far+near)/(near-far), -1.0],
114 [0.0, 0.0, (2.0*far*near)/(near-far), 0.0],
115 ]
116}
117
118pub fn mat4_mul(a: [[f32;4];4], b: [[f32;4];4]) -> [[f32;4];4] {
119 let mut r = [[0.0f32;4];4];
120 for col in 0..4 {
121 for row in 0..4 {
122 r[col][row] = a[0][row]*b[col][0] + a[1][row]*b[col][1]
123 + a[2][row]*b[col][2] + a[3][row]*b[col][3];
124 }
125 }
126 r
127}
128
129pub fn directional_light_space_matrix(
130 light_dir: [f32; 3],
131 cam_pos: [f32; 3],
132 half_extent: f32,
133) -> [[f32; 4]; 4] {
134 let len = (light_dir[0]*light_dir[0] + light_dir[1]*light_dir[1] + light_dir[2]*light_dir[2]).sqrt();
135 let dir = [light_dir[0]/len, light_dir[1]/len, light_dir[2]/len];
136 let pos = [
137 cam_pos[0] - dir[0] * half_extent,
138 cam_pos[1] - dir[1] * half_extent,
139 cam_pos[2] - dir[2] * half_extent,
140 ];
141 let up = if dir[1].abs() < 0.99 { [0.0f32, 1.0, 0.0] } else { [1.0f32, 0.0, 0.0] };
142 let view = view_matrix(&pos, &dir, &up);
143 let ortho = ortho_matrix(-half_extent, half_extent, -half_extent, half_extent, 0.1, half_extent * 2.0);
144 mat4_mul(ortho, view)
145}
146
147pub const CUBE_FACE_DIRS: [([f32;3], [f32;3]); 6] = [
149 ([1.0, 0.0, 0.0], [0.0, -1.0, 0.0]),
150 ([-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]),
151 ([0.0, 1.0, 0.0], [0.0, 0.0, 1.0]),
152 ([0.0, -1.0, 0.0], [0.0, 0.0, -1.0]),
153 ([0.0, 0.0, 1.0], [0.0, -1.0, 0.0]),
154 ([0.0, 0.0, -1.0], [0.0, -1.0, 0.0]),
155];
156
157pub fn face_viewport(face: usize, res: u32) -> glium::Rect {
159 let col = (face % 2) as u32;
160 let row = (face / 2) as u32;
161 glium::Rect {
162 left: col * res,
163 bottom: row * res,
164 width: res,
165 height: res,
166 }
167}