#mesh #geometry #io #interchange #format-conversion #import-export

meshx

一个用于转换流行网格格式的转换工具库

12个版本

0.6.1 2023年11月12日
0.6.0 2023年4月27日
0.5.2 2022年5月6日
0.5.1 2022年4月21日
0.1.3 2021年11月12日

#9 in 数据格式

Download history 7/week @ 2024-05-20 29/week @ 2024-06-03 1/week @ 2024-06-10 5/week @ 2024-06-17 18/week @ 2024-07-01 43/week @ 2024-07-29 56/week @ 2024-08-05

99每月下载量
用于 2 crates

MIT/Apache

1.5MB
15K SLoC

meshx

一个用于在流行网格格式之间提供便利转换工具的网格交换库。

On crates.io On docs.rs Build status License Downloads

免责声明:meshx 仍处于开发的早期阶段,不建议在生产环境中使用。该 meshx API 不可靠,可能会更改。

概述

这个库旨在简化不同3D应用程序之间使用网格数据结构的互操作性。 meshx 还提供常见的网格类型和相关特性,以便进行操作。

该库的不同组件可以在不同的环境下使用。以下是一些用例,meshx 可以用于

  • 从文件导入或导出网格
  • 为3D应用程序构建插件
  • 存储用于长期使用的未类型化网格数据
  • 构建用于显示网格属性的可视化工具
  • 使用熟悉的API构建适用于您应用程序的特定网格类型。有关更多详细信息,请参阅meshx 的文档。

快速教程

我们将探讨 meshx 的不同用法。

构建网格

该库包含一些内置的网格类型,例如用于三角形网格的 TriMesh,用于多边形网格的 PolyMesh 和用于四面体网格的 TetMesh,这些网格类型常用于有限元模拟。让我们从创建一个由两个三角形组成的简单三角形网格开始。

use meshx::TriMesh;

// Four corners of a [0,0]x[1,1] square in the xy-plane.
let vertices = vec![
    [0.0f64, 0.0, 0.0],
    [1.0, 0.0, 0.0],
    [0.0, 1.0, 0.0],
    [1.0, 1.0, 0.0],
];

// Two triangles making up a square.
let indices = vec![[0, 1, 2], [1, 3, 2]];

// Create the triangle mesh
// NOTE: TriMesh is generic over position type, so you need to
//       specify the specific float type somewhere.
let trimesh = TriMesh::new(vertices, indices);

简单计数查询

我们的新三角形网格将传递的顶点和索引解释为网格数据,这为我们提供了有关网格的信息。现在我们可以询问相关数量,如下所示

use meshx::topology:*; // Prepare to get topology information.

println!("number of vertices: {}", mesh.num_vertices());
println!("number of faces: {}", mesh.num_faces());
println!("number of face-edges: {}", mesh.num_face_edges());
println!("number of face-vertices: {}", mesh.num_face_vertices());

它将打印

number of vertices: 4
number of faces: 2
number of face-edges: 6
number of face-vertices: 6

在下一节中,我们将探讨 face-edgesface-vertices 的含义。

拓扑查询

我们的简单三角形网格由2个三角形表示,每个三角形指向我们4个顶点数组中的3个顶点。这种连接关系仅定义了一个三角形网格。我们可以用ASCII码可视化我们的特定示例,顶点编号在外部,三角形索引在内部

      2        3
      +--------+
      |\       |
      | \   1  |
      |  \     |
      |   \    |
      |    \   |
      |     \  |
      |  0   \ |
      |       \|
y     +--------+
^     0        1
|
+--> x

如果我们按行编号每个三角形索引,我们将得到总共6个索引。这些在meshx中被称为面顶点。对于我们的示例,我们在三角形内部写线性面顶点索引

      2        3
      +--------+
      |\5     4|
      |2\      |
      |  \     |
      |   \    |
      |    \   |
      |     \  |
      |      \3|
      |0     1\|
y     +--------+
^     0        1
|
+--> x

相应地,面边是每个面内以逆时针方向从每个面顶点开始的有向边。例如,第一个面边对应于索引0的第一个三角形中的0->1边。

这种结构可以很容易地推广到遵循类似命名约定的其他网格。我们使用单词顶点单元分别表示0、1、2和3维元素。当面和单元类型混合,如非结构化网格中(例如,Mesh类型)时,我们简单地称之为单元,以与其他库(如VTK)保持一致。

了解这一点后,我们可以在三角形网格中查询特定的面、面边、面顶点或顶点

// Get triangle indices:
println!("face 1: {:?}", mesh.face(1));

// Face-edge topology:
// These functions are provided by the FaceEdge trait.
println!("face-edge index of edge 2 on face 1: {:?}", mesh.face_edge(1, 2));
println!("edge index of face-edge 5: {:?}", mesh.edge(5));
println!("edge index of edge 2 on face 1: {:?}", mesh.face_to_edge(1, 2));

// Face-vertex topology:
// These functions are provided by the FaceVertex trait.
println!("face-vertex index of vertex 1 on face 0: {:?}", mesh.face_vertex(0, 1));
println!("vertex index of face-vertex 1: {:?}", mesh.vertex(1));
println!("vertex index of vertex 1 on face 0: {:?}", mesh.face_vertex(0, 1));

输出如下

face 1: [1, 3, 2]
face-edge index of edge 2 on face 1: Some(FaceEdgeIndex(5))
edge index of face-edge 5: EdgeIndex(2)
edge index of edge 2 on face 1: Some(EdgeIndex(2))
face-vertex index of vertex 1 on face 0: Some(FaceVertexIndex(1))
vertex index of face-vertex 1: VertexIndex(1)
vertex index of vertex 1 on face 0: Some(FaceVertexIndex(1))

目前,当给定一个元素内的索引时,拓扑查询函数返回一个Option,因为这些不是类型化的。在这种情况下,对于超出范围的索引返回None。期望类型化索引(例如,EdgeIndex、FaceVertexIndex)正确地有界。如果给出了错误的类型化索引,函数将崩溃。

FaceVertex拓扑通常用于将uvtexture坐标分配给网格。FaceEdge拓扑可以用于在网格上定义半边接口。

属性

在与3D应用程序中的网格一起工作时,能够加载和存储网格不同元素的价值是至关重要的。网格支持的每个元素(顶点、边、面或单元)或拓扑元素(例如面边、面顶点)都可以存储与该元素相关联的任何类型的值。

例如,我们可以在顶点上存储顶点法线,或在面顶点上存储纹理坐标,以指示将每个三角形映射到纹理的位置。

让我们在我们的网格顶点上添加一些指向上方(+z)且远离网格的关联向量。这可以表示物理量,如力或速度,或用于阴影的法线。

use meshx::attrib::*;

let mut mesh = mesh; // Make mesh mutable.

let vectors = vec![
    [-1.0, -1.0, 1.0],
    [1.0, -1.0, 1.0],
    [-1.0, 1.0, 1.0],
    [1.0, 1.0, 1.0],
];

mesh.insert_attrib_data::<[f32; 3], VertexIndex>("up_and_away", vectors).unwrap();

meshx支持多种操作属性的方式,包括解构网格以公开存储这些属性的结构。有关详细信息,请参阅attrib模块和attrib::Attrib特质。

IO:加载和保存网格

使用io模块,我们可以加载和存储网格。要保存我们的三角形网格到文件,我们可以简单地调用save_trimesh并指定一个路径

meshx::io::save_trimesh(&mesh, "tests/artifacts/tutorial_trimesh.vtk").unwrap();

然后可以从另一个应用程序(如ParaView)中加载它。以下是我们的网格,其中关联向量显示为箭头:TriMesh ParaView Screenshot

我们还可以使用load_trimesh加载此文件。

let loaded_mesh = meshx::io::load_trimesh("tests/artifacts/tutorial_trimesh.vtk").unwrap();

有关支持的格式,请参阅io模块。

由于顶点位置和属性恰好可以用浮点数精确表示,我们可以预期这两个网格是相同的

assert_eq!(mesh, loaded_mesh);

尽管在网格可以缓存属性数据的情况下,这不一定总是成立。

结论

在本篇简短的教程中,我们介绍了以下内容:

  • 构建网格
  • 使用 num_* 函数在网格上获取元素和连接数量
  • 访问与网格相关的各种索引
  • 在网格顶点上插入属性数据
  • 将网格保存到文件和从文件加载。

本教程中的代码可在 examples/tutorial.rs 找到,并且可以使用以下命令运行:

$ cargo run --example tutorial

有关API的更多详细信息,请参阅 文档

许可证

本存储库许可协议为以下任一:

任选其一。

依赖关系

~8MB
~156K SLoC