or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdanalysis.mdcore-operations.mdfile-io.mdindex.mdmesh-processing.mdpoint-clouds.mdspatial-queries.mdvisualization.md

mesh-processing.mddocs/

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

```