From 0585a7e2499ae94b1927aac3d5d97e85a911fa86 Mon Sep 17 00:00:00 2001 From: Tristam MacDonald Date: Mon, 18 Jan 2021 08:23:19 +0100 Subject: [PATCH 1/3] Make nested source public on CentralDifference --- src/source.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source.rs b/src/source.rs index 509484f..655bd89 100644 --- a/src/source.rs +++ b/src/source.rs @@ -33,7 +33,7 @@ pub trait HermiteSource: Source { /// Adapts a `Source` to a `HermiteSource` by deriving normals from the surface via central differencing pub struct CentralDifference { - source: S, + pub source: S, epsilon: f32, } From 6ca10556a0e62e67928a9ce6da697b03e12ccd8b Mon Sep 17 00:00:00 2001 From: Tristam MacDonald Date: Mon, 18 Jan 2021 08:25:01 +0100 Subject: [PATCH 2/3] Add some useful functions to the Vec type --- src/math.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/math.rs b/src/math.rs index 47e840d..42b4ead 100644 --- a/src/math.rs +++ b/src/math.rs @@ -48,6 +48,30 @@ impl Vec3 { z: 1.0, } } + + /// Create a vector by taking the absolute value of each component in this vector + pub fn abs(&self) -> Self { + Self { + x: self.x.abs(), + y: self.y.abs(), + z: self.z.abs(), + } + } + + /// Sum all of the components in this vector + pub fn component_sum(&self) -> f32 { + self.x + self.y + self.z + } + + /// Find the maximum value out of all components in this vector + pub fn component_max(&self) -> f32 { + self.x.max(self.y.max(self.z)) + } + + /// Find the minimum value out of all components in this vector + pub fn component_min(&self) -> f32 { + self.x.min(self.y.min(self.z)) + } } impl std::ops::Add for Vec3 { @@ -81,6 +105,13 @@ impl std::ops::Mul for Vec3 { Vec3::new(self.x * other, self.y * other, self.z * other) } } +impl std::ops::Mul for f32 { + type Output = Vec3; + + fn mul(self, other: Vec3) -> Vec3 { + Vec3::new(self * other.x, self * other.y, self * other.z) + } +} impl std::ops::Div for Vec3 { type Output = Vec3; @@ -89,3 +120,19 @@ impl std::ops::Div for Vec3 { Vec3::new(self.x / other.x, self.y / other.y, self.z / other.z) } } + +impl std::ops::Div for Vec3 { + type Output = Vec3; + + fn div(self, other: f32) -> Vec3 { + Vec3::new(self.x / other, self.y / other, self.z / other) + } +} + +impl std::ops::Div for f32 { + type Output = Vec3; + + fn div(self, other: Vec3) -> Vec3 { + Vec3::new(self / other.x, self / other.y, self / other.z) + } +} From 82fed2e1bfb6ac83dbccf970eaae1718067480f1 Mon Sep 17 00:00:00 2001 From: Tristam MacDonald Date: Mon, 18 Jan 2021 09:03:30 +0100 Subject: [PATCH 3/3] Add support for evaluating max-norm distance fields --- src/linear_hashed_marching_cubes.rs | 29 +++++++++++++++++++++++++---- src/source.rs | 10 +++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/linear_hashed_marching_cubes.rs b/src/linear_hashed_marching_cubes.rs index 84b04bb..88651f9 100644 --- a/src/linear_hashed_marching_cubes.rs +++ b/src/linear_hashed_marching_cubes.rs @@ -17,7 +17,7 @@ use crate::marching_cubes_impl::{get_offset, interpolate, march_cube}; use crate::marching_cubes_tables::EDGE_CONNECTION; use crate::math::Vec3; use crate::morton::Morton; -use crate::source::{HermiteSource, Source}; +use crate::source::{HermiteSource, Norm, Source}; use std::collections::HashMap; // Morton cube corners are ordered differently to the marching cubes tables, so remap them to match. @@ -43,15 +43,29 @@ impl Edge { /// Extracts meshes from distance fields using marching cubes over a linear hashed octree. pub struct LinearHashedMarchingCubes { max_depth: usize, + norm: Norm, } impl LinearHashedMarchingCubes { /// Create a new LinearHashedMarchingCubes. /// /// The depth of the internal octree will be at most `max_depth`, causing the tree to span the - /// equivalent of a cubic grid at most `2.pow(max_depth)` in either direction. + /// equivalent of a cubic grid at most `2.pow(max_depth)` in either direction. Distances + /// will be evaluated in Euclidean space. pub fn new(max_depth: usize) -> Self { - Self { max_depth } + Self { + max_depth, + norm: Norm::Euclidean, + } + } + + /// Create a new LinearHashedMarchingCubes. + /// + /// The depth of the internal octree will be at most `max_depth`, causing the tree to span the + /// equivalent of a cubic grid at most `2.pow(max_depth)` in either direction. Distances will + /// be evaluated in accordance with the provided Norm. + pub fn with_norm(max_depth: usize, norm: Norm) -> Self { + Self { max_depth, norm } } /// Extracts a mesh from the given [`Source`](../source/trait.Source.html). @@ -119,6 +133,13 @@ impl LinearHashedMarchingCubes { self.extract_surface(&octree, &primal_vertices, indices, &mut base_index, extract); } + fn diagonal(&self, distance: f32) -> f32 { + match self.norm { + Norm::Euclidean => distance * SQRT_OF_3, + Norm::Max => distance, + } + } + fn build_octree(&mut self, source: &S) -> LinearHashedOctree where S: Source, @@ -130,7 +151,7 @@ impl LinearHashedMarchingCubes { |key: Morton, distance: &f32| { let level = key.level(); let size = key.size(); - level < 2 || (level < max_depth && distance.abs() <= size * SQRT_OF_3) + level < 2 || (level < max_depth && distance.abs() <= self.diagonal(size)) }, |key: Morton| { let p = key.center(); diff --git a/src/source.rs b/src/source.rs index 655bd89..1560a67 100644 --- a/src/source.rs +++ b/src/source.rs @@ -14,11 +14,19 @@ use crate::math::Vec3; +/// The context in which signed distance fields should be evaluated +pub enum Norm { + /// The L^2 or Euclidean norm is the one you are used to, i.e. where l = sqrt(x^2 + y^2 + z^2). + Euclidean, + /// The L^∞ or Max norm represents Manhattan/Taxicab distance, i.e. l = max(|x|, |y|, |z|). + Max, +} + /// A source capable of sampling a signed distance field at discrete coordinates. pub trait Source { /// Samples the distance field at the given (x, y, z) coordinates. /// - /// Must return the signed distance (i.e. negative for coodinates inside the surface), + /// Must return the signed distance (i.e. negative for coordinates inside the surface), /// as our Marching Cubes implementation will evaluate the surface at the zero-crossing. fn sample(&self, x: f32, y: f32, z: f32) -> f32; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy