Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

types for hyperbolic space #420

Merged
merged 32 commits into from
Jul 28, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1376848
added MVector in math.rs generally for points and directions in
haiitsstrawberry Jul 9, 2024
eba688b
Merge branch 'master' of https://github.com/Ralith/hypermine
haiitsstrawberry Jul 13, 2024
8f3c12d
reconcile merge
haiitsstrawberry Jul 16, 2024
5e4c4dd
cleanup
haiitsstrawberry Jul 21, 2024
f4a88bc
added back lorentz_normalize() fixing the test
haiitsstrawberry Jul 21, 2024
4d4b090
decreased verbosity of some into() calls by using less verbose variat…
haiitsstrawberry Jul 23, 2024
9c0680e
removed obsolete commented out code
haiitsstrawberry Jul 24, 2024
f22b047
readd accidentally removed comment
haiitsstrawberry Jul 24, 2024
f322538
changed the definition of MVector::origin() for brevity
haiitsstrawberry Jul 24, 2024
679f3be
used dual_to_node_f64() and BOUNDING_SPHERE_RADIUS_F64 for better pre…
haiitsstrawberry Jul 24, 2024
7d048e6
formatting
haiitsstrawberry Jul 24, 2024
2d8b016
remove redundant <_>
haiitsstrawberry Jul 24, 2024
1834ae1
made wrapped definitions of used MulAssign and AddAssign more concise
haiitsstrawberry Jul 24, 2024
dc29b03
removed unused imports
haiitsstrawberry Jul 24, 2024
b9ad604
concision
haiitsstrawberry Jul 24, 2024
43f7603
check pass stuff(?)
haiitsstrawberry Jul 24, 2024
4c0d61c
simplification by deref
haiitsstrawberry Jul 27, 2024
d99b08e
simplify multiplication step
haiitsstrawberry Jul 27, 2024
9bb5b43
add inline to function
haiitsstrawberry Jul 27, 2024
1917462
group test related code together
haiitsstrawberry Jul 27, 2024
1d3b6d2
removed verbose paths having math::
haiitsstrawberry Jul 27, 2024
3de15b6
Update common/src/character_controller/collision.rs
strawberrycinnabar Jul 27, 2024
886b335
Update common/src/collision_math.rs
strawberrycinnabar Jul 27, 2024
2667a8b
Update common/src/collision_math.rs
strawberrycinnabar Jul 27, 2024
becd604
Update common/src/collision_math.rs
strawberrycinnabar Jul 27, 2024
061428c
Update common/src/plane.rs
strawberrycinnabar Jul 27, 2024
926db6e
Update common/src/plane.rs
strawberrycinnabar Jul 27, 2024
cea4366
Update common/src/traversal.rs
strawberrycinnabar Jul 27, 2024
7dbf512
Update common/src/traversal.rs
strawberrycinnabar Jul 27, 2024
4d080da
guh
haiitsstrawberry Jul 27, 2024
fe19fec
guh
haiitsstrawberry Jul 27, 2024
7012673
ok
haiitsstrawberry Jul 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions client/src/graphics/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ impl Draw {
let draw_started = Instant::now();
let view = sim.as_ref().map_or_else(Position::origin, |sim| sim.view());
let projection = frustum.projection(1.0e-4);
let view_projection = projection.matrix() * math::mtranspose(&view.local);
let view_projection = projection.matrix() * <math::MIsometry<_> as Into<na::Matrix4<_>>>::into(view.local.mtranspose());
strawberrycinnabar marked this conversation as resolved.
Show resolved Hide resolved
self.loader.drive();

let device = &*self.gfx.device;
Expand Down Expand Up @@ -482,8 +482,8 @@ impl Draw {
.expect("positionless entity in graph");
if let Some(character_model) = self.loader.get(self.character_model) {
if let Ok(ch) = sim.world.get::<&Character>(entity) {
let transform = transform
* pos.local
let transform = <math::MIsometry<_> as Into<na::Matrix4<_>>>::into(transform)
* <math::MIsometry<_> as Into<na::Matrix4<_>>>::into(pos.local)
* na::Matrix4::new_scaling(sim.cfg().meters_to_absolute)
* ch.state.orientation.to_homogeneous();
for mesh in &character_model.0 {
Expand Down
19 changes: 10 additions & 9 deletions client/src/graphics/frustum.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use common::Plane;
use common::math;

#[derive(Debug, Copy, Clone)]
pub struct Frustum {
Expand Down Expand Up @@ -79,7 +80,7 @@ pub struct FrustumPlanes {
}

impl FrustumPlanes {
pub fn contain(&self, point: &na::Vector4<f32>, radius: f32) -> bool {
pub fn contain(&self, point: &math::MVector<f32>, radius: f32) -> bool {
for &plane in &[&self.left, &self.right, &self.down, &self.up] {
if plane.distance_to(point) < -radius {
return false;
Expand All @@ -92,20 +93,20 @@ impl FrustumPlanes {
#[cfg(test)]
mod tests {
use super::*;
use common::math::{origin, translate_along};
use common::math::{translate_along, MVector};
use std::f32;

#[test]
fn planes_sanity() {
// 90 degree square
let planes = Frustum::from_vfov(f32::consts::FRAC_PI_4, 1.0).planes();
assert!(planes.contain(&origin(), 0.1));
assert!(planes.contain(&(translate_along(&-na::Vector3::z()) * origin()), 0.0));
assert!(!planes.contain(&(translate_along(&na::Vector3::z()) * origin()), 0.0));
assert!(planes.contain(&MVector::origin(), 0.1));
assert!(planes.contain(&(translate_along(&-na::Vector3::z()) * MVector::origin()), 0.0));
assert!(!planes.contain(&(translate_along(&na::Vector3::z()) * MVector::origin()), 0.0));

assert!(!planes.contain(&(translate_along(&na::Vector3::x()) * origin()), 0.0));
assert!(!planes.contain(&(translate_along(&na::Vector3::y()) * origin()), 0.0));
assert!(!planes.contain(&(translate_along(&-na::Vector3::x()) * origin()), 0.0));
assert!(!planes.contain(&(translate_along(&-na::Vector3::y()) * origin()), 0.0));
assert!(!planes.contain(&(translate_along(&na::Vector3::x()) * MVector::origin()), 0.0));
assert!(!planes.contain(&(translate_along(&na::Vector3::y()) * MVector::origin()), 0.0));
assert!(!planes.contain(&(translate_along(&-na::Vector3::x()) * MVector::origin()), 0.0));
assert!(!planes.contain(&(translate_along(&-na::Vector3::y()) * MVector::origin()), 0.0));
}
}
10 changes: 5 additions & 5 deletions client/src/graphics/voxels/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ impl Voxels {
device: &Device,
frame: &mut Frame,
sim: &mut Sim,
nearby_nodes: &[(NodeId, na::Matrix4<f32>)],
nearby_nodes: &[(NodeId, math::MIsometry<f32>)],
cmd: vk::CommandBuffer,
frustum: &Frustum,
) {
Expand Down Expand Up @@ -122,12 +122,12 @@ impl Voxels {
}
let node_scan_started = Instant::now();
let frustum_planes = frustum.planes();
let local_to_view = math::mtranspose(&view.local);
let local_to_view = view.local.mtranspose();
let mut extractions = Vec::new();
let mut workqueue_is_full = false;
for &(node, ref node_transform) in nearby_nodes {
let node_to_view = local_to_view * node_transform;
let origin = node_to_view * math::origin();
let node_to_view = local_to_view * *node_transform;
let origin = node_to_view * math::MVector::origin();
if !frustum_planes.contain(&origin, dodeca::BOUNDING_SPHERE_RADIUS) {
// Don't bother generating or drawing chunks from nodes that are wholly outside the
// frustum.
Expand Down Expand Up @@ -174,7 +174,7 @@ impl Voxels {
frame.drawn.push(slot);
// Transfer transform
frame.surface.transforms_mut()[slot.0 as usize] =
node_transform * vertex.chunk_to_node();
<math::MIsometry<_> as Into<na::Matrix4<_>>>::into(*node_transform) * vertex.chunk_to_node();
}
if let (None, &VoxelData::Dense(ref data)) = (&surface, voxels) {
// Extract a surface so it can be drawn in future frames
Expand Down
2 changes: 1 addition & 1 deletion client/src/local_character_controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl LocalCharacterController {
pub fn oriented_position(&self) -> Position {
Position {
node: self.position.node,
local: self.position.local * self.orientation.to_homogeneous(),
local: self.position.local * math::MIsometry::unit_quaternion_to_homogeneous(self.orientation),
}
}

Expand Down
3 changes: 2 additions & 1 deletion client/src/prediction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,13 @@ impl PredictedMotion {
#[cfg(test)]
mod tests {
use super::*;
use common::math::MIsometry;

/// An arbitrary position
fn pos() -> Position {
Position {
node: common::graph::NodeId::ROOT,
local: na::one(),
local: MIsometry::identity(),
}
}

Expand Down
5 changes: 3 additions & 2 deletions client/src/sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use common::{
self, BlockUpdate, Character, CharacterInput, CharacterState, Command, Component,
Inventory, Position,
},
math,
sanitize_motion_input,
world::Material,
EntityId, GraphEntities, SimConfig, Step,
Expand Down Expand Up @@ -109,7 +110,7 @@ impl Sim {
selected_material: Material::WoodPlanks,
prediction: PredictedMotion::new(proto::Position {
node: NodeId::ROOT,
local: na::one(),
local: math::MIsometry::identity(),
}),
local_character_controller: LocalCharacterController::new(),
}
Expand Down Expand Up @@ -550,7 +551,7 @@ impl Sim {
let ray_casing_result = graph_ray_casting::ray_cast(
&self.graph,
&view_position,
&Ray::new(na::Vector4::w(), -na::Vector4::z()),
&Ray::new(math::MVector::w(), -math::MVector::z()),
self.cfg.character.block_reach,
);

Expand Down
10 changes: 5 additions & 5 deletions common/src/character_controller/collision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use tracing::error;

use crate::{collision_math::Ray, graph::Graph, graph_collision, math, proto::Position};
use crate::{collision_math::Ray, graph::Graph, graph_collision, math, math::{MVector,MIsometry}, proto::Position};

/// Checks for collisions when a character moves with a character-relative displacement vector of `relative_displacement`.
pub fn check_collision(
Expand All @@ -22,7 +22,7 @@ pub fn check_collision(
let displacement_norm = displacement_sqr.sqrt();
let displacement_normalized = relative_displacement / displacement_norm;

let ray = Ray::new(math::origin(), displacement_normalized);
let ray = Ray::new(MVector::origin(), MVector::<f32>::from(displacement_normalized));
let tanh_distance = displacement_norm.tanh();

let cast_hit = graph_collision::sphere_cast(
Expand Down Expand Up @@ -58,7 +58,7 @@ pub fn check_collision(
// This normal now represents a contact point at the origin, so we omit the w-coordinate
// to ensure that it's orthogonal to the origin.
normal: na::UnitVector3::new_normalize(
(math::mtranspose(&displacement_transform) * hit.normal).xyz(),
((displacement_transform.mtranspose()) * hit.normal).xyz(),
strawberrycinnabar marked this conversation as resolved.
Show resolved Hide resolved
),
}),
}
Expand All @@ -77,7 +77,7 @@ pub struct CollisionCheckingResult {

/// Multiplying the character's position by this matrix will move the character as far as it can up to its intended
/// displacement until it hits the wall.
pub displacement_transform: na::Matrix4<f32>,
pub displacement_transform: MIsometry<f32>,

pub collision: Option<Collision>,
}
Expand All @@ -88,7 +88,7 @@ impl CollisionCheckingResult {
pub fn stationary() -> CollisionCheckingResult {
CollisionCheckingResult {
displacement_vector: na::Vector3::zeros(),
displacement_transform: na::Matrix4::identity(),
displacement_transform: MIsometry::identity(),
collision: None,
}
}
Expand Down
2 changes: 1 addition & 1 deletion common/src/character_controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub fn run_character_step(
}

// Renormalize
position.local = math::renormalize_isometry(&position.local);
position.local = position.local.renormalize_isometry();
let (next_node, transition_xf) = graph.normalize_transform(position.node, &position.local);
if next_node != position.node {
position.node = next_node;
Expand Down
85 changes: 43 additions & 42 deletions common/src/chunk_collision.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
collision_math::Ray,
math,
math::MVector,
node::{ChunkLayout, VoxelAABB, VoxelData},
voxel_math::Coords,
world::Material,
Expand All @@ -12,7 +13,7 @@ pub struct ChunkCastHit {

/// Represents the normal vector of the hit surface in the dual coordinate system of the chunk.
/// To get the actual normal vector, project it so that it is orthogonal to the endpoint in Lorentz space.
pub normal: na::Vector4<f32>,
pub normal: MVector<f32>,
}

/// Performs sphere casting (swept collision query) against the voxels in the chunk with the given `voxel_data`
Expand Down Expand Up @@ -90,10 +91,10 @@ fn find_face_collision(
for t in bounding_box.grid_planes(t_axis) {
// Find a normal to the grid plane. Note that (t, 0, 0, x) is a normal of the plane whose closest point
// to the origin is (x, 0, 0, t), and we use that fact here.
let normal = math::lorentz_normalize(&math::tuv_to_xyz(
let normal = math::tuv_to_xyz(
t_axis,
na::Vector4::new(1.0, 0.0, 0.0, layout.grid_to_dual(t)),
));
MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(t)),
).lorentz_normalize();

let Some(new_tanh_distance) =
ray.solve_sphere_plane_intersection(&normal, collider_radius.sinh())
Expand All @@ -109,7 +110,7 @@ fn find_face_collision(
// Which side we approach the plane from affects which voxel we want to use for hit detection.
// If exiting a chunk via a chunk boundary, hit detection is handled by a different chunk.
// We also want to adjust the normal vector to always face outward from the hit block
let (normal, voxel_t) = if math::mip(&ray.direction, &normal) < 0.0 {
let (normal, voxel_t) = if ray.direction.mip(&normal) < 0.0 {
if t == 0 {
continue;
}
Expand All @@ -122,7 +123,7 @@ fn find_face_collision(
};

let ray_endpoint = ray.ray_point(new_tanh_distance);
let contact_point = ray_endpoint - normal * math::mip(&ray_endpoint, &normal);
let contact_point = ray_endpoint - normal * ray_endpoint.mip(&normal);

// Compute the u and v-coordinates of the voxels at the contact point
let Some(voxel_u) = layout.dual_to_voxel(contact_point[u_axis] / contact_point.w) else {
Expand Down Expand Up @@ -169,18 +170,18 @@ fn find_edge_collision(
// Loop through all grid lines overlapping the bounding box
for (u, v) in bounding_box.grid_lines(u_axis, v_axis) {
// Compute vectors Lorentz-orthogonal to the edge and to each other
let edge_normal0 = math::lorentz_normalize(&math::tuv_to_xyz(
let edge_normal0 = math::tuv_to_xyz(
t_axis,
na::Vector4::new(0.0, 1.0, 0.0, layout.grid_to_dual(u)),
));
MVector::new(0.0, 1.0, 0.0, layout.grid_to_dual(u)),
).lorentz_normalize();

let edge_normal1 = math::tuv_to_xyz(
t_axis,
na::Vector4::new(0.0, 0.0, 1.0, layout.grid_to_dual(v)),
);
let edge_normal1 = math::lorentz_normalize(
&(edge_normal1 - edge_normal0 * math::mip(&edge_normal0, &edge_normal1)),
MVector::new(0.0, 0.0, 1.0, layout.grid_to_dual(v)),
);
let edge_normal1 =
(edge_normal1 - edge_normal0 * edge_normal0.mip(&edge_normal1))
.lorentz_normalize();

let Some(new_tanh_distance) = ray.solve_sphere_line_intersection(
&edge_normal0,
Expand All @@ -197,8 +198,8 @@ fn find_edge_collision(

let ray_endpoint = ray.ray_point(new_tanh_distance);
let contact_point = ray_endpoint
- edge_normal0 * math::mip(&ray_endpoint, &edge_normal0)
- edge_normal1 * math::mip(&ray_endpoint, &edge_normal1);
- edge_normal0 * ray_endpoint.mip(&edge_normal0)
- edge_normal1 * ray_endpoint.mip(&edge_normal1);

// Compute the t-coordinate of the voxels at the contact point
let Some(voxel_t) = layout.dual_to_voxel(contact_point[t_axis] / contact_point.w) else {
Expand Down Expand Up @@ -254,19 +255,20 @@ fn find_vertex_collision(

// Compute vectors Lorentz-orthogonal to the vertex and to each other
let vertex_normal0 =
math::lorentz_normalize(&na::Vector4::new(1.0, 0.0, 0.0, layout.grid_to_dual(x)));
MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(x))
.lorentz_normalize();

let vertex_normal1 = na::Vector4::new(0.0, 1.0, 0.0, layout.grid_to_dual(y));
let vertex_normal1 = math::lorentz_normalize(
&(vertex_normal1 - vertex_normal0 * math::mip(&vertex_normal0, &vertex_normal1)),
);
let vertex_normal1 = MVector::new(0.0, 1.0, 0.0, layout.grid_to_dual(y));
let vertex_normal1 =
(vertex_normal1 - vertex_normal0 * vertex_normal0.mip(&vertex_normal1))
.lorentz_normalize();

let vertex_normal2 = na::Vector4::new(0.0, 0.0, 1.0, layout.grid_to_dual(z));
let vertex_normal2 = math::lorentz_normalize(
&(vertex_normal2
- vertex_normal0 * math::mip(&vertex_normal0, &vertex_normal2)
- vertex_normal1 * math::mip(&vertex_normal1, &vertex_normal2)),
);
let vertex_normal2 = MVector::new(0.0, 0.0, 1.0, layout.grid_to_dual(z));
let vertex_normal2 =
(vertex_normal2
- vertex_normal0 * vertex_normal0.mip(&vertex_normal2)
- vertex_normal1 * vertex_normal1.mip(&vertex_normal2))
.lorentz_normalize();

let Some(new_tanh_distance) = ray.solve_sphere_point_intersection(
&vertex_normal0,
Expand All @@ -283,12 +285,12 @@ fn find_vertex_collision(
}

// Determine the cube-centric coordinates of the vertex
let vertex_position = math::lorentz_normalize(&na::Vector4::new(
let vertex_position = MVector::new(
layout.grid_to_dual(x),
layout.grid_to_dual(y),
layout.grid_to_dual(z),
1.0,
));
).lorentz_normalize();

// A collision was found. Update the hit.
let ray_endpoint = ray.ray_point(new_tanh_distance);
Expand Down Expand Up @@ -356,29 +358,28 @@ mod tests {
ray_end_grid_coords: [f32; 3],
wrapped_fn: impl FnOnce(&Ray, f32),
) {
let ray_start = math::lorentz_normalize(&na::Vector4::new(
let ray_start = MVector::new(
ray_start_grid_coords[0] / ctx.layout.dual_to_grid_factor(),
ray_start_grid_coords[1] / ctx.layout.dual_to_grid_factor(),
ray_start_grid_coords[2] / ctx.layout.dual_to_grid_factor(),
1.0,
));
).lorentz_normalize();

let ray_end = math::lorentz_normalize(&na::Vector4::new(
let ray_end = MVector::new(
ray_end_grid_coords[0] / ctx.layout.dual_to_grid_factor(),
ray_end_grid_coords[1] / ctx.layout.dual_to_grid_factor(),
ray_end_grid_coords[2] / ctx.layout.dual_to_grid_factor(),
1.0,
));
).lorentz_normalize();

let ray = Ray::new(
ray_start,
math::lorentz_normalize(
&((ray_end - ray_start)
+ ray_start * math::mip(&ray_start, &(ray_end - ray_start))),
),
((ray_end - ray_start)
+ ray_start * ray_start.mip(&(ray_end - ray_start)))
.lorentz_normalize(),
);

let tanh_distance = (-math::mip(&ray_start, &ray_end)).acosh();
let tanh_distance = (-ray_start.mip(&ray_end)).acosh();

wrapped_fn(&ray, tanh_distance)
}
Expand Down Expand Up @@ -518,16 +519,16 @@ mod tests {
// The ray we care about is after its start point has moved to the contact point.
let ray = math::translate(
&ray.position,
&math::lorentz_normalize(&ray.ray_point(hit.tanh_distance)),
&ray.ray_point(hit.tanh_distance).lorentz_normalize(),
) * ray;

// Project normal to be perpendicular to the ray's position
let corrected_normal = math::lorentz_normalize(
&(hit.normal + ray.position * math::mip(&hit.normal, &ray.position)),
);
let corrected_normal =
(hit.normal + ray.position * hit.normal.mip(&ray.position))
.lorentz_normalize();

// Check that the normal and ray are pointing opposite directions
assert!(math::mip(&corrected_normal, &ray.direction) < 0.0);
assert!(corrected_normal.mip(&ray.direction) < 0.0);
}

/// Tests that a suitable collision is found when approaching a single voxel from various angles and that
Expand Down
Loading
Loading