#distance-field #mesh #sdf #voxels #raymarching #graphics #voxel

mesh_to_sdf

网格到有符号距离场(SDF)转换器

3个不稳定版本

0.2.1 2024年2月18日
0.2.0 2024年2月16日
0.1.0 2024年2月5日

#145 in 数据格式

Download history 23/week @ 2024-04-21 39/week @ 2024-04-28 4/week @ 2024-05-05 33/week @ 2024-05-12 14/week @ 2024-05-19 14/week @ 2024-06-02 9/week @ 2024-06-09 3/week @ 2024-06-16 70/week @ 2024-06-23 19/week @ 2024-06-30 10/week @ 2024-07-07 24/week @ 2024-07-21

每月下载量53
用于 mesh_to_sdf_client

MIT/Apache

87KB
1.5K SLoC

mesh_to_sdf

⚠️ 此crate处于早期阶段。预计API将发生变化。


此crate提供两个入口点

  • generate_sdf:计算由 verticesindices 定义的网格在 query_points 点上的有符号距离场。
  • generate_grid_sdf:计算由 verticesindices 定义的网格上的有符号距离场。
use mesh_to_sdf::{generate_sdf, generate_grid_sdf, SignMethod, Topology, Grid};
// vertices are [f32; 3], but can be cgmath::Vector3<f32>, glam::Vec3, etc.
let vertices: Vec<[f32; 3]> = vec![[0.5, 1.5, 0.5], [1., 2., 3.], [1., 3., 7.]];
let indices: Vec<u32> = vec![0, 1, 2];

// query points must be of the same type as vertices
let query_points: Vec<[f32; 3]> = vec![[0.5, 0.5, 0.5]];

// Query points are expected to be in the same space as the mesh.
let sdf: Vec<f32> = generate_sdf(
    &vertices,
    Topology::TriangleList(Some(&indices)), // TriangleList as opposed to TriangleStrip
    &query_points,
    SignMethod::Raycast, // How the sign is computed.
);                       // Raycast is robust but requires the mesh to be watertight.

for point in query_points.iter().zip(sdf.iter()) {
    // distance is positive outside the mesh and negative inside.
    println!("Distance to {:?}: {}", point.0, point.1);
}

// if you can, use generate_grid_sdf instead of generate_sdf as it's optimized and much faster.
let bounding_box_min = [0., 0., 0.];
let bounding_box_max = [10., 10., 10.];
let cell_count = [10, 10, 10];

let grid = Grid::from_bounding_box(&bounding_box_min, &bounding_box_max, cell_count);

let sdf: Vec<f32> = generate_grid_sdf(
    &vertices,
    Topology::TriangleList(Some(&indices)),
    &grid,
    SignMethod::Raycast, // How the sign is computed.
);                       // Raycast is robust but requires the mesh to be watertight.

for x in 0..cell_count[0] {
    for y in 0..cell_count[1] {
        for z in 0..cell_count[2] {
            let index = grid.get_cell_idx(&[x, y, z]);
            log::info!("Distance to cell [{}, {}, {}]: {}", x, y, z, sdf[index as usize]);
        }
    }
}

网格拓扑

索引可以是实现 Into<u32> 的任何类型,例如 u16u32。拓扑可以是列表或条带。如果没有提供索引,则假定它们是 0..vertices.len()

对于顶点,此库旨在尽可能通用,通过提供可以针对任何类型实现的 Point 特性。大多数常见数学库的实现受功能标志控制。默认情况下,只提供 [f32; 3]。如果您找不到您喜欢的库,请随意为其实现特性并提交PR或打开问题。


计算符号

此库提供了两种计算距离符号的方法

  • SignMethod::Raycast(默认):一种计算距离符号的稳健方法。它计算从查询点发出的射线与网格三角形的交点数。它只适用于封闭网格,但保证符号正确。
  • SignMethod::Normal:它使用三角形的法线通过计算查询点方向的点积来估计符号。它适用于非封闭网格,但可能会在网格外部泄漏负距离。

对于网格生成,Raycast慢约1%。对于查询点,Raycast慢约10%。请注意,它取决于查询点/网格大小与三角形比例,但这只是一个大致的概念。


使用您最喜欢的库

要使用您最喜欢的数学库与 mesh_to_sdf,需要将其添加到 mesh_to_sdf 依赖项中。例如,要使用 glam

[dependencies]
mesh_to_sdf = { version = "0.2.1", features = ["glam"] }

目前支持以下库

  • cgmath (cgmath::Vector3<f32>)
  • glam (glam::Vec3)
  • mint (mint::Vector3<f32>mint::Point3<f32>)
  • nalgebra (nalgebra::Vector3<f32>nalgebra::Point3<f32>)
  • [f32; 3]

基准测试

generate_grid_sdf 比比 generate_sdf 快得多,应尽可能使用。 generate_sdf 不分配内存(除了结果数组),但速度较慢。计划在未来实现更快的版本。 SignMethod::Raycast 比比 SignMethod::Normal 稍慢,但更稳健,应尽可能使用(在 generate_grid_sdf 中约1%,在 generate_sdf 中约10%)。

许可证:MIT OR Apache-2.0

依赖项

~1.8–3.5MB
~76K SLoC