unify perspective/orthogonal cameras
This commit is contained in:
parent
5c6ef7c758
commit
8c0ae03add
|
|
@ -16,6 +16,39 @@ pub(crate) fn projection(fovy: f32, aspect: f32, base_distance: f32) -> Mat4 {
|
||||||
Mat4::perspective_rh(fovy, aspect, 0.1 * base_distance, 10.0 * base_distance)
|
Mat4::perspective_rh(fovy, aspect, 0.1 * base_distance, 10.0 * base_distance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Camera {
|
||||||
|
pub y_frac: f32,
|
||||||
|
pub y_angle: f32,
|
||||||
|
pub y_range: f32,
|
||||||
|
pub z_min: f32,
|
||||||
|
pub z_max: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Camera {
|
||||||
|
pub fn clamp_z_min(&mut self, min_z: f32) -> &mut Self {
|
||||||
|
let (s, c) = (0.5 * self.y_angle).sin_cos();
|
||||||
|
// let distance = 0.5 * self.y_len * c / s;
|
||||||
|
let distance_scaled = 0.5 * self.y_range * c;
|
||||||
|
if distance_scaled + self.z_min * s < min_z * s {
|
||||||
|
self.z_min = min_z - distance_scaled / s;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_mat4(&self) -> Mat4 {
|
||||||
|
let tan_fov = (0.5 * self.y_angle).tan();
|
||||||
|
let z_range = self.z_max - self.z_min;
|
||||||
|
let y_far = 0.5 * self.y_range + self.z_max * tan_fov;
|
||||||
|
let u = -y_far / z_range;
|
||||||
|
Mat4::from_cols_array_2d(&[
|
||||||
|
[self.y_frac, 0., 0., 0.],
|
||||||
|
[0., 1., 0., 0.],
|
||||||
|
[0., 0., u, -tan_fov],
|
||||||
|
[0., 0., u * self.z_min, 0.5 * self.y_range],
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -76,4 +109,33 @@ mod tests {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_proj() {
|
||||||
|
for (y_range, y_angle_deg) in [
|
||||||
|
(10.000000, 53.130102f32),
|
||||||
|
(11.547005, 60.000000f32),
|
||||||
|
(20.000000, 90.000000f32),
|
||||||
|
(34.641016, 120.000000f32),
|
||||||
|
(40.000000, 126.869898f32),
|
||||||
|
] {
|
||||||
|
let y_angle = y_angle_deg.to_radians();
|
||||||
|
let camera = Camera {
|
||||||
|
y_frac: 0.5,
|
||||||
|
y_angle,
|
||||||
|
y_range,
|
||||||
|
z_min: -9.0,
|
||||||
|
z_max: 90.0,
|
||||||
|
};
|
||||||
|
let actual = camera.to_mat4();
|
||||||
|
let expected = projection(y_angle, 1.0 / camera.y_frac, 10.0)
|
||||||
|
* Affine3A::from_translation(vec3(0., 0., -10.0));
|
||||||
|
let c = expected.x_axis.x / actual.x_axis.x;
|
||||||
|
assert!(
|
||||||
|
(c * actual).abs_diff_eq(expected, 1e-3),
|
||||||
|
"projection at {y_angle_deg}d is wrong\nexpected: {expected}\nexpected: {}\ncomputed: {actual}",
|
||||||
|
expected / c,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
src/lib.rs
17
src/lib.rs
|
|
@ -108,15 +108,22 @@ impl Core {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&self, output: &wgpu::Texture, args: &RedrawArgs) {
|
fn render(&self, output: &wgpu::Texture, args: &RedrawArgs) {
|
||||||
let aspect = {
|
let y_frac = {
|
||||||
let size = output.size();
|
let size = output.size();
|
||||||
let w = size.width as f32;
|
let w = size.width as f32;
|
||||||
let h = size.height as f32;
|
let h = size.height as f32;
|
||||||
w / h
|
h / w
|
||||||
};
|
};
|
||||||
let distance = 0.5 * args.cam_view_y / (0.5 * args.cam_view_angle).tan();
|
let proj = camera::Camera {
|
||||||
let view = Mat4::from(camera::view(args.cam_yaw, args.cam_pitch, distance));
|
y_frac,
|
||||||
let proj = camera::projection(args.cam_view_angle, aspect, distance);
|
y_angle: args.cam_view_angle,
|
||||||
|
y_range: args.cam_view_y,
|
||||||
|
z_min: -0.5 * args.cam_view_y,
|
||||||
|
z_max: 0.5 * args.cam_view_y,
|
||||||
|
}
|
||||||
|
.clamp_z_min(0.01 * args.cam_view_y)
|
||||||
|
.to_mat4();
|
||||||
|
let view = Mat4::from_mat3(camera::rotation(-args.cam_yaw, -args.cam_pitch));
|
||||||
self.mesh_pipeline.set_params(
|
self.mesh_pipeline.set_params(
|
||||||
&self.queue,
|
&self.queue,
|
||||||
render::mesh::Params {
|
render::mesh::Params {
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@
|
||||||
<number>1</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>15.000000000000000</double>
|
<double>0.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<double>150.000000000000000</double>
|
<double>150.000000000000000</double>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user