Skip to content

Commit 212f599

Browse files
committed
Add marching cubes using linear hashed octrees.
Accompanying improvements: - Refactors common code out of the base marching cubes implementation. - Adds a 3 dimensional vector class to improve readability. - Apply rustfmt to entire codebase. - Main sample now can switch algorithms, shapes, and wireframe mode on the fly. - Samples can now all be exited by pressing the ESC key.
1 parent fb19db7 commit 212f599

21 files changed

+1440
-277
lines changed

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
[package]
22
name = "isosurface"
3-
version = "0.0.3"
3+
version = "0.0.4"
44
authors = ["Tristam MacDonald <swiftcoder@gmail.com>"]
55
license = "Apache-2.0"
66
description = "Isosurface extraction algorithms"
77
repository = "https://github.com/swiftcoder/isosurface"
88
readme = "README.md"
99

1010
[dev-dependencies]
11-
glium = "0.18.0"
11+
glium = "0.17.0"
12+
glium_text_rusttype = "0.2.0"
1213
cgmath = "0.15.0"
1314

1415
[profile.dev]

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
# Isosurface
2-
Isosurface extraction algorithms for Rust. Currently only a few techniques are implemented, fancier algorithms to be added at a later date.
2+
Isosurface extraction algorithms for Rust. Currently only a few techniques are implemented.
33

4-
This crate has no dependencies, although the example relies on the glium, cgmath, num crates.
4+
This crate intentionally has no dependencies to keep the footprint of the library small. The examples rely on the `glium`, `glium_text_rusttype`, and `cgmath` crates.
55

66
# Marching Cubes
7-
The Marching Cubes implementation produces perfectly indexed meshes with no duplicate vertices, through the use of a (fairly involved) index caching system. The complexity of the cache could no doubt be reduced through some clever arithmetic, but it is not currently a bottleneck.
7+
The Marching Cubes implementation produces perfectly indexed meshes with few duplicate vertices, through the use of a (fairly involved) index caching system. The complexity of the cache could no doubt be reduced through some clever arithmetic, but it is not currently a bottleneck.
88

99
The implementation has been optimised for performance, with memory use kept as a low as possible considering. For an NxNxN voxel chunk, it will allocate roughly NxN of f32 storage for isosurface values, and Nx(N+1) of u32 storage for the index cache.
1010

11-
Indices are 32-bit becuase for chunks of 32x32 and larger you'll typically end up with mor than 65k vertices. If you are targetting a mobile platform that supports only 16-bit indices, you'll need to use smaller chunk sizes, and truncate on the output side.
11+
Indices are 32-bit because for chunks of 32x32 and larger you'll typically end up with more than 65k vertices. If you are targeting a mobile platform that supports only 16-bit indices, you'll need to use smaller chunk sizes, and truncate on the output side.
1212

13+
# Linear Hashed Marching Cubes
14+
A very efficient algorithm using interleaved integer coordinates to represent octree cells, and storing them in a hash table. Results in better mesh quality than regular marching cubes, and is significantly faster. Memory usage is less predictable, but shouldn't be significantly higher than standard marching cubes.
15+
1316
# Point Clouds and Deferred Rasterisation
1417
Point cloud extraction is typically not all that useful, given that point clouds don't contain any data about the actual surface. However, Gavan Woolery (gavanw@) posted an interesting image of reconstructing surface data in image space on the GPU, so I've added a simple example of that.
1518

examples/common/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2017 Tristam MacDonald
1+
// Copyright 2018 Tristam MacDonald
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
pub mod sources;
16+
pub mod text;
1617

1718
use std::slice;
1819
use std::mem;
@@ -21,10 +22,8 @@ use std::mem;
2122
/// copying. It is optimal, but it is also punching holes in the type system. I hope that Rust
2223
/// provides safe functionality to handle this in the future. In the meantime, reproduce
2324
/// this workaround at your own risk.
24-
pub fn reinterpret_cast_slice<S, T>(input : &[S]) -> &[T] {
25+
pub fn reinterpret_cast_slice<S, T>(input: &[S]) -> &[T] {
2526
let length_in_bytes = input.len() * mem::size_of::<S>();
2627
let desired_length = length_in_bytes / mem::size_of::<T>();
27-
unsafe {
28-
slice::from_raw_parts(input.as_ptr() as *const T, desired_length)
29-
}
28+
unsafe { slice::from_raw_parts(input.as_ptr() as *const T, desired_length) }
3029
}

examples/common/sources.rs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2017 Tristam MacDonald
1+
// Copyright 2018 Tristam MacDonald
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -17,18 +17,64 @@
1717
use isosurface::source::Source;
1818

1919
/// The distance-field equation for a torus
20-
fn torus(x : f32, y : f32, z : f32) -> f32 {
21-
const R1 : f32 = 1.0 / 4.0;
22-
const R2 : f32 = 1.0 / 10.0;
23-
let q_x = ((x*x + y*y).sqrt()).abs() - R1;
24-
let len = (q_x*q_x + z*z).sqrt();
20+
fn torus(x: f32, y: f32, z: f32) -> f32 {
21+
const R1: f32 = 1.0 / 4.0;
22+
const R2: f32 = 1.0 / 10.0;
23+
let q_x = ((x * x + y * y).sqrt()).abs() - R1;
24+
let len = (q_x * q_x + z * z).sqrt();
2525
len - R2
2626
}
2727

2828
pub struct Torus {}
2929

3030
impl Source for Torus {
31-
fn sample(&self, x : f32, y : f32, z : f32) -> f32 {
31+
fn sample(&self, x: f32, y: f32, z: f32) -> f32 {
3232
torus(x - 0.5, y - 0.5, z - 0.5)
3333
}
3434
}
35+
36+
fn abs(x: f32, y: f32, z: f32) -> (f32, f32, f32) {
37+
(
38+
if x > 0.0 { x } else { -x },
39+
if y > 0.0 { y } else { -y },
40+
if z > 0.0 { z } else { -z },
41+
)
42+
}
43+
44+
fn max(px: f32, py: f32, pz: f32, qx: f32, qy: f32, qz: f32) -> (f32, f32, f32) {
45+
(
46+
if px > qx { px } else { qx },
47+
if py > qy { py } else { qy },
48+
if pz > qz { pz } else { qz },
49+
)
50+
}
51+
52+
/// The distance field equation for a cube
53+
fn cube(px: f32, py: f32, pz: f32, bx: f32, by: f32, bz: f32) -> f32 {
54+
let (ax, ay, az) = abs(px, py, pz);
55+
let (dx, dy, dz) = (ax - bx, ay - by, az - bz);
56+
let (mx, my, mz) = max(dx, dy, dz, 0.0, 0.0, 0.0);
57+
let l = (mx * mx + my * my + mz * mz).sqrt();
58+
dx.max(dz.max(dy)).min(0.0) + l
59+
}
60+
61+
/// The distance field equation for a sphere
62+
fn sphere(x: f32, y: f32, z: f32, r: f32) -> f32 {
63+
(x * x + y * y + z * z).sqrt() - r
64+
}
65+
66+
/// Subtract one distance field from another (i.e. CSG difference operation)
67+
fn subtract(d1: f32, d2: f32) -> f32 {
68+
d2.max(-d1)
69+
}
70+
71+
pub struct CubeSphere {}
72+
73+
impl Source for CubeSphere {
74+
fn sample(&self, x: f32, y: f32, z: f32) -> f32 {
75+
subtract(
76+
sphere(x - 0.5, y - 0.5, z - 0.5, 0.25),
77+
cube(x - 0.5, y - 0.5, z - 0.5, 0.2, 0.2, 0.2),
78+
)
79+
}
80+
}

examples/common/text.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2018 Tristam MacDonald
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//! Conveniences to make the `glium_text` API easier to use in samples.
16+
17+
use cgmath::{Matrix4, Vector3};
18+
19+
/// Produce a transform matrix that will display text at offset column `x`, row `y`, in a
20+
/// display-filling coordinate space N characters wide and N*aspect rows high.
21+
pub fn layout_text(characters_per_row: f32, aspect: f32, x: f32, y: f32) -> Matrix4<f32> {
22+
let inv_scale = 2.0 / characters_per_row;
23+
Matrix4::from_translation(Vector3::new(-1.0, -1.0, 0.0))
24+
* Matrix4::from_nonuniform_scale(inv_scale, inv_scale * aspect, 1.0)
25+
* Matrix4::from_translation(Vector3::new(x, y, 0.0))
26+
}

0 commit comments

Comments
 (0)
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