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 数据格式
99每月下载量
用于 2 crates
1.5MB
15K SLoC
meshx
一个用于在流行网格格式之间提供便利转换工具的网格交换库。
免责声明: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-edges
和 face-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
拓扑通常用于将uv
或texture
坐标分配给网格。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)中加载它。以下是我们的网格,其中关联向量显示为箭头:
我们还可以使用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的更多详细信息,请参阅 文档。
许可证
本存储库许可协议为以下任一:
- Apache License,版本 2.0,(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT 或 https://opensource.org/licenses/MIT)
任选其一。
依赖关系
~8MB
~156K SLoC