#[derive(Debug, Clone, Copy)]
pub struct Intrinsics {
pub fx: f32,
pub fy: f32,
pub cx: f32,
pub cy: f32,
}
#[derive(Debug, Clone)]
pub struct Camera {
pub intrinsics: Intrinsics,
pub view_matrix: [f32; 16],
pub proj_matrix: [f32; 16],
pub position: [f32; 3],
}
impl Camera {
pub fn look_at(
eye: [f32; 3],
target: [f32; 3],
up: [f32; 3],
intrinsics: Intrinsics,
width: u32,
height: u32,
near: f32,
far: f32,
) -> Self {
let view_matrix = look_at_rh(eye, target, up);
let proj_matrix = perspective(
intrinsics.fx,
intrinsics.fy,
intrinsics.cx,
intrinsics.cy,
width,
height,
near,
far,
);
Self {
intrinsics,
view_matrix,
proj_matrix,
position: eye,
}
}
pub fn as_uniform(&self) -> CameraUniform {
CameraUniform {
view_matrix: self.view_matrix,
proj_matrix: self.proj_matrix,
camera_position: self.position,
_pad: 0.0,
focal: [self.intrinsics.fx, self.intrinsics.fy],
principal: [self.intrinsics.cx, self.intrinsics.cy],
}
}
}
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C)]
pub struct CameraUniform {
pub view_matrix: [f32; 16],
pub proj_matrix: [f32; 16],
pub camera_position: [f32; 3],
pub _pad: f32,
pub focal: [f32; 2],
pub principal: [f32; 2],
}
fn look_at_rh(eye: [f32; 3], target: [f32; 3], up: [f32; 3]) -> [f32; 16] {
let f = normalize(sub(target, eye));
let s = normalize(cross(f, up));
let u = cross(s, f);
[
s[0],
u[0],
-f[0],
0.0,
s[1],
u[1],
-f[1],
0.0,
s[2],
u[2],
-f[2],
0.0,
-dot(s, eye),
-dot(u, eye),
dot(f, eye),
1.0,
]
}
fn perspective(
fx: f32,
fy: f32,
cx: f32,
cy: f32,
width: u32,
height: u32,
near: f32,
far: f32,
) -> [f32; 16] {
let w = width as f32;
let h = height as f32;
[
2.0 * fx / w,
0.0,
0.0,
0.0,
0.0,
2.0 * fy / h,
0.0,
0.0,
1.0 - 2.0 * cx / w,
2.0 * cy / h - 1.0,
-(far + near) / (far - near),
-1.0,
0.0,
0.0,
-2.0 * far * near / (far - near),
0.0,
]
}
fn sub(a: [f32; 3], b: [f32; 3]) -> [f32; 3] {
[a[0] - b[0], a[1] - b[1], a[2] - b[2]]
}
fn cross(a: [f32; 3], b: [f32; 3]) -> [f32; 3] {
[
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
a[0] * b[1] - a[1] * b[0],
]
}
fn dot(a: [f32; 3], b: [f32; 3]) -> f32 {
a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
fn normalize(v: [f32; 3]) -> [f32; 3] {
let len = dot(v, v).sqrt();
[v[0] / len, v[1] / len, v[2] / len]
}