1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use cgmath::{EuclideanSpace, SquareMatrix, Zero};
use pill_engine::internal::{
TransformComponent,
CameraComponent
};
use anyhow::{ Result };
use wgpu::util::DeviceExt;
use std::f32::consts::FRAC_PI_2;
#[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.0, 0.0, 0.5, 1.0,
);
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub(crate) struct CameraUniform {
pub(crate) position: [f32; 4],
pub(crate) view_projection_matrix: [[f32; 4]; 4],
}
impl CameraUniform {
pub fn new() -> Self {
Self {
position: cgmath::Vector4::zero().into(),
view_projection_matrix: cgmath::Matrix4::identity().into(),
}
}
pub fn update_data(&mut self, camera_component: &CameraComponent, transform_component: &TransformComponent) {
self.position = cgmath::Vector4::<f32> {
x: transform_component.position.x,
y: transform_component.position.y,
z: transform_component.position.z,
w: 0.0
}.into();
self.view_projection_matrix = (CameraUniform::calculate_projection_matrix(camera_component) * CameraUniform::calculate_view_matrix(transform_component)).into();
}
fn calculate_view_matrix(transform_component: &TransformComponent) -> cgmath::Matrix4::<f32> {
let position = cgmath::Point3::from_vec(transform_component.position);
let roll_matrix = cgmath::Matrix3::from_angle_z(cgmath::Deg(transform_component.rotation.z));
let yaw_matrix = cgmath::Matrix3::from_angle_y(cgmath::Deg(transform_component.rotation.y));
let pitch_matrix = cgmath::Matrix3::from_angle_x(cgmath::Deg(transform_component.rotation.x));
let rotation_matrix = yaw_matrix * pitch_matrix * roll_matrix;
let direction = rotation_matrix * cgmath::Vector3::<f32>::unit_z();
cgmath::Matrix4::look_to_rh(
position,
direction,
cgmath::Vector3::unit_y()
)
}
fn calculate_projection_matrix(camera_component: &CameraComponent) -> cgmath::Matrix4::<f32> {
OPENGL_TO_WGPU_MATRIX * cgmath::perspective(
cgmath::Deg(camera_component.fov),
camera_component.aspect.get_value(),
camera_component.range.start,
camera_component.range.end
)
}
}
#[derive(Debug)]
pub struct RendererCamera {
pub(crate) uniform: CameraUniform,
buffer: wgpu::Buffer,
pub bind_group: wgpu::BindGroup,
}
impl RendererCamera {
pub fn new(device: &wgpu::Device, camera_bind_group_layout: &wgpu::BindGroupLayout) -> Result<Self> {
let uniform = CameraUniform::new();
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("camera_buffer"),
contents: bytemuck::cast_slice(&[uniform]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &camera_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: buffer.as_entire_binding(),
}],
label: Some("camera_bind_group"),
});
let camera = Self {
uniform,
buffer,
bind_group,
};
Ok(camera)
}
pub fn update(&mut self, queue: &wgpu::Queue, camera_component: &CameraComponent, transform_component: &TransformComponent) {
self.uniform.update_data(camera_component, transform_component);
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[self.uniform]));
}
}