0
# Mesh Processing and Modification
1
2
Advanced mesh processing capabilities including repair operations, boolean operations, remeshing, subdivision, and mesh quality improvement. These functions enable comprehensive mesh manipulation and enhancement workflows.
3
4
## Capabilities
5
6
### Boolean Operations
7
8
Perform CSG (Constructive Solid Geometry) operations between meshes.
9
10
```python { .api }
11
def union(self, other, engine=None, check_volume=True, **kwargs) -> 'Trimesh':
12
"""
13
Boolean union with another mesh.
14
15
Parameters:
16
- other: Trimesh object or sequence of Trimesh objects to union with
17
- engine: str, boolean engine ('manifold' or 'blender')
18
- check_volume: bool, check that all meshes are watertight volumes
19
- **kwargs: boolean operation options
20
21
Returns:
22
New Trimesh object containing the union
23
"""
24
25
def intersection(self, other, engine=None, check_volume=True, **kwargs) -> 'Trimesh':
26
"""
27
Boolean intersection with another mesh.
28
29
Parameters:
30
- other: Trimesh object or sequence of Trimesh objects to intersect with
31
- engine: str, boolean engine ('manifold' or 'blender')
32
- check_volume: bool, check that all meshes are watertight volumes
33
- **kwargs: boolean operation options
34
35
Returns:
36
New Trimesh object containing the intersection
37
"""
38
39
def difference(self, other, engine=None, check_volume=True, **kwargs) -> 'Trimesh':
40
"""
41
Boolean difference (subtraction) with another mesh.
42
43
Parameters:
44
- other: Trimesh object or sequence of Trimesh objects to subtract
45
- engine: str, boolean engine ('manifold' or 'blender')
46
- check_volume: bool, check that all meshes are watertight volumes
47
- **kwargs: boolean operation options
48
49
Returns:
50
New Trimesh object with other subtracted from self
51
"""
52
53
```
54
55
### Mesh Repair and Healing
56
57
Fix common mesh problems and improve mesh quality.
58
59
```python { .api }
60
def fix_normals(self) -> None:
61
"""Fix face winding order to ensure consistent normals"""
62
63
def fill_holes(self) -> bool:
64
"""
65
Fill holes in the mesh surface.
66
67
Returns:
68
bool, True if holes were filled
69
"""
70
71
72
def remove_duplicate_faces(self) -> None:
73
"""Remove faces that are duplicated"""
74
75
def remove_degenerate_faces(self, height=1e-12) -> None:
76
"""
77
Remove degenerate faces (zero area or invalid).
78
79
Parameters:
80
- height: float, minimum face area threshold
81
"""
82
83
def remove_unreferenced_vertices(self) -> None:
84
"""Remove vertices not referenced by any face"""
85
86
def merge_vertices(self, merge_tex=False, merge_norm=False, digits_vertex=None) -> None:
87
"""
88
Merge vertices closer than tolerance.
89
90
Parameters:
91
- merge_tex: bool, merge texture coordinates
92
- merge_norm: bool, merge vertex normals
93
- digits_vertex: int, decimal places for vertex precision
94
"""
95
96
def process(self, validate=True, merge_tex=False, merge_norm=False) -> None:
97
"""
98
Apply standard mesh processing pipeline.
99
100
Parameters:
101
- validate: bool, run mesh validation
102
- merge_tex: bool, merge texture coordinates
103
- merge_norm: bool, merge vertex normals
104
"""
105
```
106
107
### Remeshing and Subdivision
108
109
Modify mesh resolution and topology.
110
111
```python { .api }
112
def subdivide(self, face_index=None) -> 'Trimesh':
113
"""
114
Subdivide mesh faces to increase resolution.
115
116
Parameters:
117
- face_index: array of face indices to subdivide (None for all)
118
119
Returns:
120
New subdivided mesh
121
"""
122
123
def subdivide_loop(self, iterations=1) -> 'Trimesh':
124
"""
125
Apply Loop subdivision for smooth surfaces.
126
127
Parameters:
128
- iterations: int, number of subdivision iterations
129
130
Returns:
131
Subdivided mesh with smooth surface
132
"""
133
134
def smoothed(self, **kwargs) -> 'Trimesh':
135
"""
136
Return smoothed version using Laplacian smoothing.
137
138
Parameters:
139
- **kwargs: smoothing parameters
140
141
Returns:
142
Smoothed mesh
143
"""
144
145
def simplify_quadratic_decimation(self, face_count=None, **kwargs) -> 'Trimesh':
146
"""
147
Simplify mesh using quadratic error decimation.
148
149
Parameters:
150
- face_count: int, target number of faces
151
- **kwargs: decimation options
152
153
Returns:
154
Simplified mesh
155
"""
156
```
157
158
### Convex Operations
159
160
Work with convex hulls and convex decomposition.
161
162
```python { .api }
163
@property
164
def convex_hull(self) -> 'Trimesh':
165
"""Convex hull of the mesh vertices"""
166
167
def convex_decomposition(self, **kwargs) -> list:
168
"""
169
Decompose mesh into convex components.
170
171
Parameters:
172
- **kwargs: decomposition parameters
173
174
Returns:
175
List of convex Trimesh objects
176
"""
177
178
def is_convex(self) -> bool:
179
"""Check if mesh is convex"""
180
```
181
182
### Mesh Slicing and Sectioning
183
184
Cut meshes with planes and extract cross-sections.
185
186
```python { .api }
187
def slice_plane(self, plane_normal, plane_origin, **kwargs):
188
"""
189
Slice mesh with a plane.
190
191
Parameters:
192
- plane_normal: (3,) plane normal vector
193
- plane_origin: (3,) point on plane
194
- **kwargs: slicing options
195
196
Returns:
197
List of mesh pieces or cross-section paths
198
"""
199
200
def section(self, plane_normal, plane_origin) -> 'Path3D':
201
"""
202
Get 2D cross-section of mesh at plane.
203
204
Parameters:
205
- plane_normal: (3,) plane normal vector
206
- plane_origin: (3,) point on plane
207
208
Returns:
209
Path3D object representing cross-section
210
"""
211
212
def section_multiplane(self, plane_normal, plane_origins) -> list:
213
"""
214
Get multiple parallel cross-sections.
215
216
Parameters:
217
- plane_normal: (3,) plane normal vector
218
- plane_origins: (n, 3) points on planes
219
220
Returns:
221
List of Path3D cross-section objects
222
"""
223
```
224
225
### Smoothing Operations
226
227
Apply various smoothing algorithms to improve mesh quality.
228
229
```python { .api }
230
def smooth_laplacian(self, lamb=0.5, iterations=1, implicit_time_integration=False, volume_constraint=True) -> 'Trimesh':
231
"""
232
Laplacian mesh smoothing.
233
234
Parameters:
235
- lamb: float, smoothing strength (0-1)
236
- iterations: int, number of smoothing iterations
237
- implicit_time_integration: bool, use implicit integration
238
- volume_constraint: bool, preserve volume during smoothing
239
240
Returns:
241
Smoothed mesh
242
"""
243
244
def smooth_taubin(self, lamb=0.5, mu=-0.53, iterations=10) -> 'Trimesh':
245
"""
246
Taubin smoothing (reduces shrinkage compared to Laplacian).
247
248
Parameters:
249
- lamb: float, positive smoothing factor
250
- mu: float, negative smoothing factor
251
- iterations: int, number of iterations
252
253
Returns:
254
Smoothed mesh
255
"""
256
```
257
258
### Mesh Registration and Alignment
259
260
Align meshes to each other or to coordinate systems.
261
262
```python { .api }
263
def register(self, other, samples=500, scale=False, icp_first=10, icp_final=50) -> tuple:
264
"""
265
Register mesh to another using ICP algorithm.
266
267
Parameters:
268
- other: Trimesh to register to
269
- samples: int, number of sample points
270
- scale: bool, allow scaling transformation
271
- icp_first: int, iterations for initial ICP
272
- icp_final: int, iterations for final ICP
273
274
Returns:
275
tuple: (transform_matrix, cost, iterations)
276
"""
277
278
def rezero(self) -> 'Trimesh':
279
"""Center mesh at origin"""
280
281
def apply_obb(self) -> 'Trimesh':
282
"""Apply oriented bounding box transformation"""
283
284
def principal_inertia_transform(self) -> np.ndarray:
285
"""Get transformation matrix aligning to principal inertia axes"""
286
```
287
288
### Mesh Generation and Modification
289
290
Create new mesh geometry and modify existing meshes.
291
292
```python { .api }
293
def extrude_polygon(polygon, height, **kwargs) -> 'Trimesh':
294
"""
295
Extrude 2D polygon to create 3D mesh.
296
297
Parameters:
298
- polygon: Path2D or (n, 2) polygon vertices
299
- height: float, extrusion height
300
- **kwargs: extrusion options
301
302
Returns:
303
Extruded Trimesh object
304
"""
305
306
def extrude_path(self, path, **kwargs) -> 'Trimesh':
307
"""
308
Extrude mesh along path.
309
310
Parameters:
311
- path: Path3D or (n, 3) path points
312
- **kwargs: extrusion options
313
314
Returns:
315
Extruded mesh
316
"""
317
318
def thicken(self, thickness, **kwargs) -> 'Trimesh':
319
"""
320
Thicken surface mesh to create solid.
321
322
Parameters:
323
- thickness: float, thickness amount
324
- **kwargs: thickening options
325
326
Returns:
327
Thickened solid mesh
328
"""
329
```
330
331
## Usage Examples
332
333
### Boolean Operations
334
335
```python
336
import trimesh
337
338
# Create primitive shapes
339
box = trimesh.primitives.Box(extents=[2, 2, 2])
340
sphere = trimesh.primitives.Sphere(radius=1.5)
341
cylinder = trimesh.primitives.Cylinder(radius=0.5, height=3)
342
343
# Boolean operations
344
union_result = box.union(sphere)
345
intersection_result = box.intersection(sphere)
346
difference_result = box.difference(cylinder)
347
348
# Chain operations
349
complex_shape = box.union(sphere).difference(cylinder)
350
351
# Check results
352
print(f"Original box volume: {box.volume}")
353
print(f"Union volume: {union_result.volume}")
354
print(f"Intersection volume: {intersection_result.volume}")
355
```
356
357
### Mesh Repair and Processing
358
359
```python
360
# Load a potentially problematic mesh
361
mesh = trimesh.load('broken_model.stl')
362
363
print(f"Initial: {len(mesh.vertices)} vertices, {len(mesh.faces)} faces")
364
print(f"Is watertight: {mesh.is_watertight}")
365
366
# Apply repair operations
367
mesh.remove_duplicate_faces()
368
mesh.remove_degenerate_faces()
369
mesh.remove_unreferenced_vertices()
370
mesh.fill_holes()
371
mesh.fix_normals()
372
373
# Merge nearby vertices
374
mesh.merge_vertices()
375
376
# Full processing pipeline
377
mesh.process(validate=True)
378
379
print(f"After repair: {len(mesh.vertices)} vertices, {len(mesh.faces)} faces")
380
print(f"Is watertight: {mesh.is_watertight}")
381
```
382
383
### Subdivision and Smoothing
384
385
```python
386
# Load base mesh
387
mesh = trimesh.load('low_poly_model.obj')
388
389
# Subdivision for higher resolution
390
high_res = mesh.subdivide_loop(iterations=2)
391
print(f"Original: {len(mesh.faces)} faces")
392
print(f"After subdivision: {len(high_res.faces)} faces")
393
394
# Smoothing operations
395
laplacian_smooth = mesh.smooth_laplacian(lamb=0.6, iterations=5)
396
taubin_smooth = mesh.smooth_taubin(iterations=10)
397
398
# Compare results
399
mesh.show() # Original
400
laplacian_smooth.show() # Laplacian smoothed
401
taubin_smooth.show() # Taubin smoothed
402
```
403
404
### Mesh Slicing
405
406
```python
407
import numpy as np
408
409
# Slice mesh with horizontal planes
410
plane_normal = np.array([0, 0, 1]) # Z-axis
411
plane_origins = np.array([[0, 0, z] for z in np.linspace(-1, 1, 10)])
412
413
# Get cross-sections
414
sections = mesh.section_multiplane(plane_normal, plane_origins)
415
416
# Export each section
417
for i, section in enumerate(sections):
418
if section is not None:
419
section.export(f'section_{i}.svg')
420
421
# Slice mesh in half
422
plane_origin = np.array([0, 0, 0])
423
pieces = mesh.slice_plane(plane_normal, plane_origin)
424
if len(pieces) == 2:
425
pieces[0].export('bottom_half.stl')
426
pieces[1].export('top_half.stl')
427
```
428
429
### Mesh Registration
430
431
```python
432
# Register two similar meshes
433
mesh1 = trimesh.load('scan1.ply')
434
mesh2 = trimesh.load('scan2.ply')
435
436
# Perform registration
437
transform, cost, iterations = mesh1.register(mesh2, samples=1000)
438
439
print(f"Registration cost: {cost}")
440
print(f"Iterations: {iterations}")
441
442
# Apply transformation
443
mesh1.apply_transform(transform)
444
445
# Check alignment quality
446
aligned_mesh = mesh1.copy()
447
distance = np.mean(aligned_mesh.nearest.vertex(mesh2.vertices)[1])
448
print(f"Mean distance after alignment: {distance}")
449
```