1use glam::{Mat4, Vec3};
6use loam_math::hyperbolic::{hyperboloid_to_klein, poincare_to_hyperboloid, poincare_to_klein};
7pub use loam_math::hyperbolic::{H3_DEPTH_ENVELOPE, H3_DEPTH_SEPARATION, H3_EYE_CHART_REACH};
8use loam_math::{Iso3, Iso3H};
9use loam_runtime::{Eye, Rigid};
10use wgpu::{CompareFunction, TextureFormat};
11
12pub const DEPTH_FORMAT: TextureFormat = TextureFormat::Depth32Float;
13pub const DEPTH_COMPARE: CompareFunction = CompareFunction::GreaterEqual;
14pub const DEPTH_CLEAR: f32 = 0.0;
15
16pub fn root_projection(fov_y: f32, aspect: f32, near: f32) -> Mat4 {
17 Mat4::perspective_infinite_reverse_rh(fov_y, aspect, near)
18}
19
20pub fn projective_depth(image: Vec3, near: f32) -> f32 {
21 near / -image.z
22}
23
24pub fn root_view_projection(eye: &Eye) -> Mat4 {
25 let basis = Mat4::from_cols(
26 Vec3::from(eye.right).extend(0.0),
27 Vec3::from(eye.up).extend(0.0),
28 (-Vec3::from(eye.forward)).extend(0.0),
29 Vec3::from(eye.position).extend(1.0),
30 );
31 root_projection(eye.fov_y, eye.aspect, eye.near) * basis.inverse()
32}
33
34pub fn eye_relative(eye: Iso3) -> Mat4 {
35 Mat4::from_rotation_translation(eye.rotation, eye.translation).inverse()
36}
37
38pub fn placement_matrix(placement: Rigid) -> Mat4 {
39 Mat4::from_scale_rotation_translation(
40 Vec3::splat(placement.scale),
41 placement.pose.rotation,
42 placement.pose.translation,
43 )
44}
45
46pub fn placed_view_projection(eye: &Eye, placement: Rigid) -> Mat4 {
47 root_view_projection(eye) * placement_matrix(placement)
48}
49
50pub fn h3_image_of(eye_inverse: &Iso3H, p: Vec3) -> Vec3 {
51 hyperboloid_to_klein(eye_inverse.matrix * poincare_to_hyperboloid(p))
52}
53
54pub fn klein_tessellate_segment(p0: Vec3, p1: Vec3, samples: usize, mut emit: impl FnMut(Vec3)) {
55 let samples = samples.max(1);
56 for i in 0..=samples {
57 emit(poincare_to_klein(p0.lerp(p1, i as f32 / samples as f32)));
58 }
59}
60
61pub fn klein_tessellation_error(p0: Vec3, p1: Vec3, samples: usize) -> f32 {
63 let reach = p0.length().max(p1.length());
64 2.5 * (p1 - p0).length_squared() * reach / (samples.max(1) as f32).powi(2)
65}