or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdfile-loading.mdindex.mdmaterials.mdmesh-operations.mdvisualization.md

mesh-operations.mddocs/

0

# Mesh Operations

1

2

Mesh organization and face data collection for 3D geometry analysis and processing. Meshes group materials and optionally collect triangulated face topology.

3

4

## Capabilities

5

6

### Mesh Objects

7

8

Meshes organize materials and optionally store face topology data for 3D geometry analysis.

9

10

```python { .api }

11

class Mesh:

12

def __init__(

13

self,

14

name: str = None,

15

has_faces: bool = False

16

):

17

"""

18

Create a mesh object for grouping materials and faces.

19

20

Parameters:

21

- name: Optional mesh name (from 'o' statements in .obj files)

22

- has_faces: Whether to collect triangulated face data

23

24

Attributes:

25

- name: str - Mesh name (None for anonymous meshes)

26

- materials: List[Material] - Materials used by this mesh

27

- has_faces: bool - Whether face data is collected

28

- faces: List[List[int]] - Triangle face data (vertex indices) if has_faces=True

29

"""

30

31

def add_material(self, material: Material) -> None:

32

"""

33

Add a material to the mesh if not already present.

34

35

Parameters:

36

- material: Material object to associate with this mesh

37

"""

38

39

def has_material(self, material: Material) -> bool:

40

"""

41

Check if mesh already contains a specific material.

42

43

Parameters:

44

- material: Material to check for

45

46

Returns:

47

- bool: True if material is already in the mesh

48

"""

49

```

50

51

### Face Data Collection

52

53

When `collect_faces=True` is used during loading, meshes collect triangulated face topology data.

54

55

**Face Data Structure:**

56

- Each face is represented as a list of 3 vertex indices (triangulated)

57

- Indices reference positions in the global `wavefront.vertices` array

58

- N-gon faces are automatically triangulated using fan triangulation

59

- Face data enables topology analysis, normal calculation, and mesh processing

60

61

**Triangulation Algorithm:**

62

For faces with n vertices (n ≥ 3) in order v₁, v₂, v₃, ..., vₙ:

63

1. First triangle: (v₁, v₂, v₃)

64

2. Additional triangles: (vⱼ, v₁, vⱼ₋₁) for j > 3

65

66

This creates a triangle fan from the first vertex, suitable for convex polygons.

67

68

### Mesh Organization

69

70

PyWavefront maintains meshes in two collections:

71

72

**Named Meshes (`wavefront.meshes`):**

73

- Dictionary mapping mesh names to Mesh objects

74

- Created from 'o' (object) statements in .obj files

75

- Accessible by name for specific mesh operations

76

77

**Mesh List (`wavefront.mesh_list`):**

78

- Ordered list of all meshes including anonymous ones

79

- Preserves order of appearance in .obj file

80

- Includes meshes without explicit names

81

82

### Usage Examples

83

84

```python

85

# Access all meshes

86

for mesh in scene.mesh_list:

87

print(f"Mesh: {mesh.name or 'Anonymous'}")

88

print(f"Materials: {len(mesh.materials)}")

89

90

if mesh.has_faces:

91

print(f"Faces: {len(mesh.faces)}")

92

93

# Access named meshes

94

if 'body' in scene.meshes:

95

body_mesh = scene.meshes['body']

96

print(f"Body mesh has {len(body_mesh.materials)} materials")

97

98

# Analyze face topology (when collect_faces=True)

99

scene = pywavefront.Wavefront('model.obj', collect_faces=True)

100

101

for mesh in scene.mesh_list:

102

if mesh.has_faces:

103

print(f"Mesh {mesh.name}: {len(mesh.faces)} triangular faces")

104

105

# Access individual faces

106

for i, face in enumerate(mesh.faces[:5]): # First 5 faces

107

v1_idx, v2_idx, v3_idx = face

108

# Get vertex positions

109

v1 = scene.vertices[v1_idx]

110

v2 = scene.vertices[v2_idx]

111

v3 = scene.vertices[v3_idx]

112

print(f"Face {i}: vertices {v1_idx}, {v2_idx}, {v3_idx}")

113

114

# Material analysis per mesh

115

for mesh_name, mesh in scene.meshes.items():

116

print(f"\nMesh: {mesh_name}")

117

118

for material in mesh.materials:

119

vertex_count = len(material.vertices) // get_vertex_size(material.vertex_format)

120

print(f" Material {material.name}: {vertex_count} vertices")

121

print(f" Format: {material.vertex_format}")

122

123

def get_vertex_size(format_str):

124

"""Helper to calculate vertex size from format string."""

125

components = format_str.split('_')

126

size = 0

127

for comp in components:

128

if comp == 'T2F': size += 2 # Texture coordinates

129

elif comp == 'C3F': size += 3 # Colors

130

elif comp == 'N3F': size += 3 # Normals

131

elif comp == 'V3F': size += 3 # Positions

132

return size

133

134

# Mesh creation and manipulation

135

new_mesh = pywavefront.Mesh("custom_mesh", has_faces=True)

136

new_mesh.add_material(some_material)

137

scene.add_mesh(new_mesh)

138

139

# Check for material overlap between meshes

140

mesh1 = scene.meshes['mesh_a']

141

mesh2 = scene.meshes['mesh_b']

142

143

shared_materials = []

144

for mat1 in mesh1.materials:

145

if mesh2.has_material(mat1):

146

shared_materials.append(mat1.name)

147

148

print(f"Shared materials: {shared_materials}")

149

```

150

151

### Face Data Applications

152

153

Face topology data enables various 3D processing tasks:

154

155

**Mesh Analysis:**

156

- Surface area calculation

157

- Volume computation for closed meshes

158

- Connectivity analysis

159

- Edge detection and boundary identification

160

161

**Normal Calculation:**

162

- Per-face normal computation

163

- Vertex normal averaging

164

- Smooth vs. flat shading determination

165

166

**Mesh Processing:**

167

- Subdivision algorithms

168

- Decimation and simplification

169

- Mesh repair and validation

170

- UV unwrapping preparation

171

172

**Collision Detection:**

173

- Bounding box generation

174

- Ray-triangle intersection

175

- Mesh-mesh collision detection

176

- Spatial acceleration structure building

177

178

```python

179

# Example: Calculate face normals

180

import numpy as np

181

182

def calculate_face_normal(v1, v2, v3):

183

"""Calculate normal vector for a triangle face."""

184

edge1 = np.array(v2) - np.array(v1)

185

edge2 = np.array(v3) - np.array(v1)

186

normal = np.cross(edge1, edge2)

187

return normal / np.linalg.norm(normal)

188

189

# Calculate normals for all faces

190

scene = pywavefront.Wavefront('model.obj', collect_faces=True)

191

192

for mesh in scene.mesh_list:

193

if mesh.has_faces:

194

face_normals = []

195

196

for face in mesh.faces:

197

v1_idx, v2_idx, v3_idx = face

198

v1 = scene.vertices[v1_idx * 3:(v1_idx * 3) + 3] # x,y,z

199

v2 = scene.vertices[v2_idx * 3:(v2_idx * 3) + 3]

200

v3 = scene.vertices[v3_idx * 3:(v3_idx * 3) + 3]

201

202

normal = calculate_face_normal(v1, v2, v3)

203

face_normals.append(normal)

204

205

print(f"Calculated {len(face_normals)} face normals for {mesh.name}")

206

```