use openxr as xr;
pub struct XrFrameContext {
pub frame_state: xr::FrameState,
pub views: Vec<xr::View>,
pub image_index: u32,
pub player_position: nalgebra_glm::Vec3,
pub player_yaw: f32,
}
impl XrFrameContext {
pub fn view_matrix(&self, eye_index: usize) -> nalgebra_glm::Mat4 {
let view = &self.views[eye_index];
let pose = &view.pose;
let rotation = {
let orientation = pose.orientation;
let flip_x = nalgebra_glm::quat_angle_axis(
180.0_f32.to_radians(),
&nalgebra_glm::vec3(1.0, 0.0, 0.0),
);
let openxr_quat =
nalgebra_glm::quat(orientation.w, orientation.z, orientation.y, orientation.x);
let player_rotation =
nalgebra_glm::quat_angle_axis(self.player_yaw, &nalgebra_glm::vec3(0.0, 1.0, 0.0));
player_rotation * flip_x * openxr_quat
};
let local_x = -pose.position.x;
let local_z = -pose.position.z;
let rotated_x = local_x * self.player_yaw.cos() + local_z * self.player_yaw.sin();
let rotated_z = -local_x * self.player_yaw.sin() + local_z * self.player_yaw.cos();
let translation = nalgebra_glm::vec3(rotated_x, pose.position.y, rotated_z);
let eye = translation + self.player_position;
let target =
eye + nalgebra_glm::quat_rotate_vec3(&rotation, &nalgebra_glm::vec3(0.0, 0.0, 1.0));
let up = nalgebra_glm::quat_rotate_vec3(&rotation, &nalgebra_glm::vec3(0.0, 1.0, 0.0));
nalgebra_glm::look_at_rh(&eye, &target, &up)
}
pub fn projection_matrix(&self, eye_index: usize) -> nalgebra_glm::Mat4 {
let view = &self.views[eye_index];
let fov = &view.fov;
let tan_left = fov.angle_left.tan();
let tan_right = fov.angle_right.tan();
let tan_up = fov.angle_up.tan();
let tan_down = fov.angle_down.tan();
let near = 0.1_f32;
let tan_width = tan_right - tan_left;
let tan_height = tan_up - tan_down;
let a11 = 2.0 / tan_width;
let a22 = 2.0 / tan_height;
let a31 = (tan_right + tan_left) / tan_width;
let a32 = (tan_up + tan_down) / tan_height;
let mut proj = nalgebra_glm::Mat4::zeros();
proj[(0, 0)] = a11;
proj[(1, 1)] = a22;
proj[(0, 2)] = a31;
proj[(1, 2)] = a32;
proj[(2, 2)] = 0.0;
proj[(2, 3)] = near;
proj[(3, 2)] = -1.0;
proj
}
pub fn camera_position(&self, eye_index: usize) -> nalgebra_glm::Vec3 {
let view = &self.views[eye_index];
let pose = &view.pose;
let local_x = -pose.position.x;
let local_z = -pose.position.z;
let rotated_x = local_x * self.player_yaw.cos() + local_z * self.player_yaw.sin();
let rotated_z = -local_x * self.player_yaw.sin() + local_z * self.player_yaw.cos();
let translation = nalgebra_glm::vec3(rotated_x, pose.position.y, rotated_z);
translation + self.player_position
}
pub fn eye_count(&self) -> usize {
self.views.len()
}
}