use wgpu::{BindGroup, BindGroupLayout, Buffer};
use wgpu::util::DeviceExt;
use crate::renderer::ctx::Gpu;
#[allow(unused)]
pub struct Camera {
inner: CameraInner,
uniform: CameraUniform,
buffer: Buffer,
bind_group: BindGroup,
bind_group_layout: BindGroupLayout,
}
impl Camera {
pub fn new(gpu: &mut Gpu, width: f32, height: f32) -> Self {
let inner = CameraInner::new(width, height);
let mut uniform = CameraUniform::new();
uniform.update_view_proj(&inner);
let buffer = gpu.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_layout = gpu.device().create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}
],
label: Some("bind_group_layout"),
});
let bind_group = gpu.device().create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: buffer.as_entire_binding(),
}
],
label: Some("camera_bind_group"),
});
Self {
inner,
uniform,
buffer,
bind_group,
bind_group_layout,
}
}
pub fn bind_group(&self) -> &BindGroup {
&self.bind_group
}
pub fn bind_group_layout(&self) -> &BindGroupLayout {
&self.bind_group_layout
}
}
pub(crate) struct CameraInner {
eye: cgmath::Point3<f32>,
target: cgmath::Point3<f32>,
up: cgmath::Vector3<f32>,
aspect: f32,
fovy: f32,
znear: f32,
zfar: f32,
}
pub(crate) const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::from_cols(
cgmath::Vector4::new(1.0, 0.0, 0.0, 0.0),
cgmath::Vector4::new(0.0, 1.0, 0.0, 0.0),
cgmath::Vector4::new(0.0, 0.0, 0.5, 0.0),
cgmath::Vector4::new(0.0, 0.0, 0.5, 1.0),
);
impl CameraInner {
pub fn new(width: f32, height: f32) -> Self {
Self {
eye: (0.0, 1.0, 2.0).into(),
target: (0.0, 0.0, 0.0).into(),
up: cgmath::Vector3::unit_y(),
aspect: width / height,
fovy: 45.0,
znear: 0.1,
zfar: 100.0,
}
}
pub fn build_view_projection_matrix(&self) -> cgmath::Matrix4<f32> {
let view = cgmath::Matrix4::look_at_rh(self.eye, self.target, self.up);
let proj = cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar);
OPENGL_TO_WGPU_MATRIX * proj * view
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct CameraUniform {
view_proj: [[f32; 4]; 4],
}
impl CameraUniform {
fn new() -> Self {
use cgmath::SquareMatrix;
Self {
view_proj: cgmath::Matrix4::identity().into(),
}
}
#[allow(unused)]
fn update_view_proj(&mut self, camera: &CameraInner) {
self.view_proj = camera.build_view_projection_matrix().into();
}
}