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

Default to f32 instead of f64, removing unnecessary casts #360

Merged
merged 3 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 3 additions & 5 deletions client/src/graphics/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,11 +431,9 @@ impl Draw {
}

if let Some(sim) = sim.as_deref() {
for (node, transform) in nearby_nodes(
&sim.graph,
&view,
f64::from(self.cfg.local_simulation.view_distance),
) {
for (node, transform) in
nearby_nodes(&sim.graph, &view, self.cfg.local_simulation.view_distance)
{
for &entity in sim.graph_entities.get(node) {
if sim.local_character == Some(entity) {
// Don't draw ourself
Expand Down
6 changes: 3 additions & 3 deletions client/src/graphics/voxels/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl Voxels {
let mut nodes = nearby_nodes(
&sim.graph,
&view,
f64::from(self.config.local_simulation.view_distance),
self.config.local_simulation.view_distance,
);
histogram!("frame.cpu.voxels.graph_traversal").record(graph_traversal_started.elapsed());
// Sort nodes by distance to the view to prioritize loading closer data and improve early Z
Expand All @@ -142,7 +142,7 @@ impl Voxels {
for &(node, ref node_transform) in &nodes {
let node_to_view = local_to_view * node_transform;
let origin = node_to_view * math::origin();
if !frustum_planes.contain(&origin, dodeca::BOUNDING_SPHERE_RADIUS as f32) {
if !frustum_planes.contain(&origin, dodeca::BOUNDING_SPHERE_RADIUS) {
// Don't bother generating or drawing chunks from nodes that are wholly outside the
// frustum.
continue;
Expand Down Expand Up @@ -183,7 +183,7 @@ impl Voxels {
frame.drawn.push(slot);
// Transfer transform
frame.surface.transforms_mut()[slot.0 as usize] =
node_transform * vertex.chunk_to_node().map(|x| x as f32);
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
124 changes: 89 additions & 35 deletions common/src/dodeca.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,32 @@ impl Side {

/// Outward normal vector of this side
#[inline]
pub fn normal(self) -> &'static na::Vector4<f64> {
&SIDE_NORMALS[self as usize]
pub fn normal(self) -> &'static na::Vector4<f32> {
&SIDE_NORMALS_F32[self as usize]
}

/// Outward normal vector of this side
#[inline]
pub fn normal_f64(self) -> &'static na::Vector4<f64> {
&SIDE_NORMALS_F64[self as usize]
}

/// Reflection across this side
#[inline]
pub fn reflection(self) -> &'static na::Matrix4<f32> {
&REFLECTIONS_F32[self as usize]
}

/// Reflection across this side
#[inline]
pub fn reflection(self) -> &'static na::Matrix4<f64> {
&REFLECTIONS[self as usize]
pub fn reflection_f64(self) -> &'static na::Matrix4<f64> {
&REFLECTIONS_F64[self as usize]
}

/// Whether `p` is opposite the dodecahedron across the plane containing `self`
#[inline]
pub fn is_facing<N: na::RealField + Copy>(self, p: &na::Vector4<N>) -> bool {
let r = na::convert::<_, na::RowVector4<N>>(self.reflection().row(3).clone_owned());
let r = na::convert::<_, na::RowVector4<N>>(self.reflection_f64().row(3).clone_owned());
(r * p).x < p.w
}
}
Expand Down Expand Up @@ -138,37 +150,71 @@ impl Vertex {
}

/// Transform from euclidean chunk coordinates to hyperbolic node space
pub fn chunk_to_node(self) -> na::Matrix4<f64> {
pub fn chunk_to_node(self) -> na::Matrix4<f32> {
self.dual_to_node() * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor())
}

/// Transform from euclidean chunk coordinates to hyperbolic node space
pub fn chunk_to_node_f64(self) -> na::Matrix4<f64> {
self.dual_to_node_f64() * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor_f64())
}

/// Transform from hyperbolic node space to euclidean chunk coordinates
pub fn node_to_chunk(self) -> na::Matrix4<f64> {
pub fn node_to_chunk(self) -> na::Matrix4<f32> {
na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * self.node_to_dual()
}

/// Transform from hyperbolic node space to euclidean chunk coordinates
pub fn node_to_chunk_f64(self) -> na::Matrix4<f64> {
na::Matrix4::new_scaling(Self::dual_to_chunk_factor_f64()) * self.node_to_dual_f64()
}

/// Transform from cube-centric coordinates to dodeca-centric coordinates
pub fn dual_to_node(self) -> &'static na::Matrix4<f64> {
&DUAL_TO_NODE[self as usize]
pub fn dual_to_node(self) -> &'static na::Matrix4<f32> {
&DUAL_TO_NODE_F32[self as usize]
}

/// Transform from cube-centric coordinates to dodeca-centric coordinates
pub fn dual_to_node_f64(self) -> &'static na::Matrix4<f64> {
&DUAL_TO_NODE_F64[self as usize]
}

/// Transform from dodeca-centric coordinates to cube-centric coordinates
pub fn node_to_dual(self) -> &'static na::Matrix4<f32> {
&NODE_TO_DUAL_F32[self as usize]
}

/// Transform from dodeca-centric coordinates to cube-centric coordinates
pub fn node_to_dual(self) -> &'static na::Matrix4<f64> {
&NODE_TO_DUAL[self as usize]
pub fn node_to_dual_f64(self) -> &'static na::Matrix4<f64> {
&NODE_TO_DUAL_F64[self as usize]
}

/// Scale factor used in conversion from cube-centric coordinates to euclidean chunk coordinates.
/// Scaling the x, y, and z components of a vector in cube-centric coordinates by this value
/// and dividing them by the w coordinate will yield euclidean chunk coordinates.
pub fn dual_to_chunk_factor() -> f64 {
*DUAL_TO_CHUNK_FACTOR
pub fn dual_to_chunk_factor() -> f32 {
*DUAL_TO_CHUNK_FACTOR_F32
}

/// Scale factor used in conversion from cube-centric coordinates to euclidean chunk coordinates.
/// Scaling the x, y, and z components of a vector in cube-centric coordinates by this value
/// and dividing them by the w coordinate will yield euclidean chunk coordinates.
pub fn dual_to_chunk_factor_f64() -> f64 {
*DUAL_TO_CHUNK_FACTOR_F64
}

/// Scale factor used in conversion from euclidean chunk coordinates to cube-centric coordinates.
/// Scaling the x, y, and z components of a vector in homogeneous euclidean chunk coordinates by this value
/// and lorentz-normalizing the result will yield cube-centric coordinates.
pub fn chunk_to_dual_factor() -> f64 {
*CHUNK_TO_DUAL_FACTOR
pub fn chunk_to_dual_factor() -> f32 {
*CHUNK_TO_DUAL_FACTOR_F32
}

/// Scale factor used in conversion from euclidean chunk coordinates to cube-centric coordinates.
/// Scaling the x, y, and z components of a vector in homogeneous euclidean chunk coordinates by this value
/// and lorentz-normalizing the result will yield cube-centric coordinates.
pub fn chunk_to_dual_factor_f64() -> f64 {
*CHUNK_TO_DUAL_FACTOR_F64
}

/// Convenience method for `self.chunk_to_node().determinant() < 0`.
Expand All @@ -179,15 +225,16 @@ impl Vertex {

pub const VERTEX_COUNT: usize = 20;
pub const SIDE_COUNT: usize = 12;
pub const BOUNDING_SPHERE_RADIUS: f64 = 1.2264568712514068;
pub const BOUNDING_SPHERE_RADIUS_F64: f64 = 1.2264568712514068;
pub const BOUNDING_SPHERE_RADIUS: f32 = BOUNDING_SPHERE_RADIUS_F64 as f32;

lazy_static! {
/// Whether two sides share an edge
static ref ADJACENT: [[bool; SIDE_COUNT]; SIDE_COUNT] = {
let mut result = [[false; SIDE_COUNT]; SIDE_COUNT];
for i in 0..SIDE_COUNT {
for j in 0..SIDE_COUNT {
let cosh_distance = (REFLECTIONS[i] * REFLECTIONS[j])[(3, 3)];
let cosh_distance = (REFLECTIONS_F64[i] * REFLECTIONS_F64[j])[(3, 3)];
// Possile cosh_distances: 1, 4.23606 = 2+sqrt(5), 9.47213 = 5+2*sqrt(5), 12.70820 = 6+3*sqrt(5);
// < 2.0 indicates identical faces; < 5.0 indicates adjacent faces; > 5.0 indicates non-adjacent faces
result[i][j] = (2.0..5.0).contains(&cosh_distance);
Expand All @@ -197,7 +244,7 @@ lazy_static! {
};

/// Vector corresponding to the outer normal of each side
static ref SIDE_NORMALS: [na::Vector4<f64>; SIDE_COUNT] = {
static ref SIDE_NORMALS_F64: [na::Vector4<f64>; SIDE_COUNT] = {
let phi = libm::sqrt(1.25) + 0.5; // golden ratio
let f = math::lorentz_normalize(&na::Vector4::new(1.0, phi, 0.0, libm::sqrt(phi)));

Expand All @@ -219,8 +266,8 @@ lazy_static! {
};

/// Transform that moves from a neighbor to a reference node, for each side
static ref REFLECTIONS: [na::Matrix4<f64>; SIDE_COUNT] = {
SIDE_NORMALS.map(|r| math::reflect(&r))
static ref REFLECTIONS_F64: [na::Matrix4<f64>; SIDE_COUNT] = {
SIDE_NORMALS_F64.map(|r| math::reflect(&r))
};

/// Sides incident to a vertex, in canonical order
Expand Down Expand Up @@ -267,26 +314,26 @@ lazy_static! {
};

/// Transform that converts from cube-centric coordinates to dodeca-centric coordinates
static ref DUAL_TO_NODE: [na::Matrix4<f64>; VERTEX_COUNT] = {
let mip_origin_normal = math::mip(&math::origin(), &SIDE_NORMALS[0]); // This value is the same for every side
static ref DUAL_TO_NODE_F64: [na::Matrix4<f64>; VERTEX_COUNT] = {
let mip_origin_normal = math::mip(&math::origin(), &SIDE_NORMALS_F64[0]); // This value is the same for every side
let mut result = [na::zero(); VERTEX_COUNT];
for i in 0..VERTEX_COUNT {
let [a, b, c] = VERTEX_SIDES[i];
let vertex_position = math::lorentz_normalize(
&(math::origin() - (a.normal() + b.normal() + c.normal()) * mip_origin_normal),
&(math::origin() - (a.normal_f64() + b.normal_f64() + c.normal_f64()) * mip_origin_normal),
);
result[i] = na::Matrix4::from_columns(&[-a.normal(), -b.normal(), -c.normal(), vertex_position]);
result[i] = na::Matrix4::from_columns(&[-a.normal_f64(), -b.normal_f64(), -c.normal_f64(), vertex_position]);
}
result
};

/// Transform that converts from dodeca-centric coordinates to cube-centric coordinates
static ref NODE_TO_DUAL: [na::Matrix4<f64>; VERTEX_COUNT] = {
DUAL_TO_NODE.map(|m| math::mtranspose(&m))
static ref NODE_TO_DUAL_F64: [na::Matrix4<f64>; VERTEX_COUNT] = {
DUAL_TO_NODE_F64.map(|m| math::mtranspose(&m))
};

static ref DUAL_TO_CHUNK_FACTOR: f64 = (2.0 + 5.0f64.sqrt()).sqrt();
static ref CHUNK_TO_DUAL_FACTOR: f64 = 1.0 / *DUAL_TO_CHUNK_FACTOR;
static ref DUAL_TO_CHUNK_FACTOR_F64: f64 = (2.0 + 5.0f64.sqrt()).sqrt();
static ref CHUNK_TO_DUAL_FACTOR_F64: f64 = 1.0 / *DUAL_TO_CHUNK_FACTOR_F64;

/// Vertex shared by 3 sides
static ref SIDES_TO_VERTEX: [[[Option<Vertex>; SIDE_COUNT]; SIDE_COUNT]; SIDE_COUNT] = {
Expand Down Expand Up @@ -321,11 +368,18 @@ lazy_static! {
let mut result = [false; VERTEX_COUNT];

for v in Vertex::iter() {
result[v as usize] = math::parity(&v.chunk_to_node());
result[v as usize] = math::parity(&v.chunk_to_node_f64());
}

result
};

static ref SIDE_NORMALS_F32: [na::Vector4<f32>; SIDE_COUNT] = SIDE_NORMALS_F64.map(|n| n.cast());
static ref REFLECTIONS_F32: [na::Matrix4<f32>; SIDE_COUNT] = REFLECTIONS_F64.map(|n| n.cast());
static ref DUAL_TO_NODE_F32: [na::Matrix4<f32>; VERTEX_COUNT] = DUAL_TO_NODE_F64.map(|n| n.cast());
static ref NODE_TO_DUAL_F32: [na::Matrix4<f32>; VERTEX_COUNT] = NODE_TO_DUAL_F64.map(|n| n.cast());
static ref DUAL_TO_CHUNK_FACTOR_F32: f32 = *DUAL_TO_CHUNK_FACTOR_F64 as f32;
static ref CHUNK_TO_DUAL_FACTOR_F32: f32 = *CHUNK_TO_DUAL_FACTOR_F64 as f32;
}

#[cfg(test)]
Expand Down Expand Up @@ -371,15 +425,15 @@ mod tests {

#[test]
fn radius() {
let corner = Vertex::A.chunk_to_node() * math::origin();
let corner = Vertex::A.chunk_to_node_f64() * math::origin();
assert_abs_diff_eq!(
BOUNDING_SPHERE_RADIUS,
BOUNDING_SPHERE_RADIUS_F64,
math::distance(&corner, &math::origin()),
epsilon = 1e-10
);
let phi = (1.0 + 5.0f64.sqrt()) / 2.0; // Golden ratio
assert_abs_diff_eq!(
BOUNDING_SPHERE_RADIUS,
BOUNDING_SPHERE_RADIUS_F64,
(1.5 * phi).sqrt().asinh(),
epsilon = 1e-10
);
Expand All @@ -389,7 +443,7 @@ mod tests {
fn chunk_to_node() {
// Chunk coordinates of (1, 1, 1) should be at the center of a dodecahedron.
let mut chunk_corner_in_node_coordinates =
Vertex::A.chunk_to_node() * na::Vector4::new(1.0, 1.0, 1.0, 1.0);
Vertex::A.chunk_to_node_f64() * na::Vector4::new(1.0, 1.0, 1.0, 1.0);
chunk_corner_in_node_coordinates /= chunk_corner_in_node_coordinates.w;
assert_abs_diff_eq!(
chunk_corner_in_node_coordinates,
Expand All @@ -401,8 +455,8 @@ mod tests {
#[test]
fn node_to_chunk() {
assert_abs_diff_eq!(
Vertex::A.chunk_to_node().try_inverse().unwrap(),
Vertex::A.node_to_chunk(),
Vertex::A.chunk_to_node_f64().try_inverse().unwrap(),
Vertex::A.node_to_chunk_f64(),
epsilon = 1e-10
);
}
Expand Down
2 changes: 1 addition & 1 deletion common/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ impl Graph {
None => continue,
Some(x) => x,
};
let mat = na::convert::<_, na::Matrix4<T>>(*side.reflection());
let mat = na::convert::<_, na::Matrix4<T>>(*side.reflection_f64());
location = mat * location;
transform = mat * transform;
continue 'outer;
Expand Down
8 changes: 4 additions & 4 deletions common/src/graph_collision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ mod tests {
let chosen_chunk_transform: na::Matrix4<f32> =
self.chosen_voxel.node_path.iter().fold(
na::Matrix4::identity(),
|transform: na::Matrix4<f32>, side| transform * side.reflection().cast::<f32>(),
) * self.chosen_voxel.vertex.dual_to_node().cast();
|transform: na::Matrix4<f32>, side| transform * side.reflection(),
) * self.chosen_voxel.vertex.dual_to_node();

let dual_to_grid_factor = graph.layout().dual_to_grid_factor();
let ray_target = chosen_chunk_transform
Expand All @@ -184,7 +184,7 @@ mod tests {
1.0,
));

let ray_position = Vertex::A.dual_to_node().cast()
let ray_position = Vertex::A.dual_to_node()
* math::lorentz_normalize(&na::Vector4::new(
self.start_chunk_relative_grid_ray_start[0] / dual_to_grid_factor,
self.start_chunk_relative_grid_ray_start[1] / dual_to_grid_factor,
Expand Down Expand Up @@ -435,7 +435,7 @@ mod tests {
}

// The node coordinates of the corner of the missing node
let vertex_pos = Vertex::A.dual_to_node().cast::<f32>() * math::origin();
let vertex_pos = Vertex::A.dual_to_node() * math::origin();

// Use a ray starting from the origin. The direction vector is vertex_pos with the w coordinate
// set to 0 and normalized
Expand Down
2 changes: 1 addition & 1 deletion common/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ impl ChunkLayout {
pub fn new(dimension: u8) -> Self {
ChunkLayout {
dimension,
dual_to_grid_factor: Vertex::dual_to_chunk_factor() as f32 * dimension as f32,
dual_to_grid_factor: Vertex::dual_to_chunk_factor() * dimension as f32,
}
}

Expand Down
6 changes: 3 additions & 3 deletions common/src/plane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl From<Side> for Plane<f64> {
/// A surface overlapping with a particular dodecahedron side
fn from(side: Side) -> Self {
Self {
normal: *side.normal(),
normal: *side.normal_f64(),
}
}
}
Expand All @@ -42,7 +42,7 @@ impl Mul<Plane<f64>> for Side {
type Output = Plane<f64>;
/// Reflect a plane across the side
fn mul(self, rhs: Plane<f64>) -> Plane<f64> {
self.reflection() * rhs
self.reflection_f64() * rhs
}
}

Expand Down Expand Up @@ -72,7 +72,7 @@ impl<N: na::RealField + Copy> Plane<N> {
impl Plane<f64> {
/// Like `distance_to`, but using chunk coordinates for a chunk in the same node space
pub fn distance_to_chunk(&self, chunk: Vertex, coord: &na::Vector3<f64>) -> f64 {
let pos = lorentz_normalize(&(chunk.chunk_to_node() * coord.push(1.0)));
let pos = lorentz_normalize(&(chunk.chunk_to_node_f64() * coord.push(1.0)));
self.distance_to(&pos)
}
}
Expand Down
4 changes: 2 additions & 2 deletions common/src/sim_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ fn meters_to_absolute(chunk_size: u8, voxel_size: f32) -> f32 {
let a = dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(1.0, 0.5, 0.5, 1.0);
let b = dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(0.0, 0.5, 0.5, 1.0);
let minimum_chunk_face_separation = math::distance(&a, &b);
let absolute_voxel_size = minimum_chunk_face_separation / f64::from(chunk_size);
absolute_voxel_size as f32 / voxel_size
let absolute_voxel_size = minimum_chunk_face_separation / f32::from(chunk_size);
absolute_voxel_size / voxel_size
}

/// Static configuration information relevant to character physics as provided in configuration files
Expand Down
Loading
Loading