0
# Visualization and Rendering
1
2
Optional OpenGL-based visualization using pyglet for displaying loaded 3D models. Supports lighting, textures, and various rendering modes.
3
4
## Installation Requirements
5
6
The visualization module requires pyglet:
7
8
```bash
9
pip install pyglet
10
# or install with visualization extras
11
pip install PyWavefront[visualization]
12
```
13
14
## Capabilities
15
16
### Drawing Functions
17
18
High-level drawing functions for rendering Wavefront objects, materials, and material collections.
19
20
```python { .api }
21
def draw(
22
instance,
23
lighting_enabled: bool = True,
24
textures_enabled: bool = True
25
) -> None:
26
"""
27
Generic draw function for various PyWavefront objects.
28
29
Parameters:
30
- instance: Wavefront, Material, or dict of materials to draw
31
- lighting_enabled: Enable OpenGL lighting calculations
32
- textures_enabled: Enable texture mapping
33
34
Supports:
35
- Wavefront objects (draws all materials)
36
- Individual Material objects
37
- Dictionary of materials {name: material}
38
"""
39
40
def draw_materials(
41
materials: Dict[str, Material],
42
lighting_enabled: bool = True,
43
textures_enabled: bool = True
44
) -> None:
45
"""
46
Draw a dictionary of materials.
47
48
Parameters:
49
- materials: Dictionary mapping material names to Material objects
50
- lighting_enabled: Enable lighting
51
- textures_enabled: Enable textures
52
"""
53
54
def draw_material(
55
material: Material,
56
face = GL_FRONT_AND_BACK,
57
lighting_enabled: bool = True,
58
textures_enabled: bool = True
59
) -> None:
60
"""
61
Draw a single material with OpenGL.
62
63
Parameters:
64
- material: Material object to render
65
- face: OpenGL face culling mode (GL_FRONT, GL_BACK, GL_FRONT_AND_BACK)
66
- lighting_enabled: Enable lighting calculations
67
- textures_enabled: Enable texture mapping
68
69
Automatically handles:
70
- Vertex format interpretation
71
- Texture binding and application
72
- Material property setup (diffuse, ambient, specular)
73
- OpenGL state management
74
"""
75
```
76
77
### Supported Vertex Formats
78
79
The visualization module supports the following vertex formats:
80
81
- `V3F` - Positions only
82
- `C3F_V3F` - Colors + positions
83
- `N3F_V3F` - Normals + positions
84
- `T2F_V3F` - Texture coordinates + positions
85
- `T2F_C3F_V3F` - Texture coordinates + colors + positions
86
- `T2F_N3F_V3F` - Texture coordinates + normals + positions
87
88
**Note:** Some formats like `C3F_N3F_V3F` and `T2F_C3F_N3F_V3F` are not supported by pyglet and will raise a ValueError.
89
90
### Texture Management
91
92
The visualization system automatically handles texture loading and binding:
93
94
```python { .api }
95
def bind_texture(texture: Texture) -> None:
96
"""
97
Bind a texture for OpenGL rendering.
98
Automatically loads texture from file if not already loaded.
99
"""
100
```
101
102
**Texture Features:**
103
- Automatic texture loading from file paths
104
- Support for various image formats (PNG, JPEG, BMP, etc.)
105
- Non-power-of-two (NPOT) texture support
106
- Automatic texture coordinate application
107
- Fallback to ambient textures when diffuse unavailable
108
109
### Material Rendering
110
111
Material properties are automatically applied during rendering:
112
113
**Lighting Properties:**
114
- Diffuse color (`material.diffuse`)
115
- Ambient color (`material.ambient`)
116
- Specular color (`material.specular`)
117
- Emissive color (`material.emissive`)
118
- Shininess (`material.shininess`)
119
120
**Transparency:**
121
- Alpha blending based on `material.transparency`
122
- Proper depth sorting for transparent objects
123
124
### Complete Rendering Example
125
126
```python
127
import pyglet
128
from pyglet.gl import *
129
import pywavefront
130
from pywavefront import visualization
131
132
# Load a 3D model
133
model_path = 'path/to/model.obj'
134
scene = pywavefront.Wavefront(model_path)
135
136
# Create a pyglet window
137
window = pyglet.window.Window(width=800, height=600, resizable=True)
138
139
# Setup OpenGL lighting
140
def setup_lighting():
141
glEnable(GL_LIGHTING)
142
glEnable(GL_LIGHT0)
143
144
# Light position
145
light_pos = (GLfloat * 4)(1.0, 1.0, 1.0, 0.0)
146
glLightfv(GL_LIGHT0, GL_POSITION, light_pos)
147
148
# Light colors
149
white_light = (GLfloat * 4)(1.0, 1.0, 1.0, 1.0)
150
glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light)
151
glLightfv(GL_LIGHT0, GL_SPECULAR, white_light)
152
153
@window.event
154
def on_resize(width, height):
155
"""Handle window resize."""
156
glViewport(0, 0, width, height)
157
158
glMatrixMode(GL_PROJECTION)
159
glLoadIdentity()
160
gluPerspective(60.0, width / height, 0.1, 100.0)
161
162
glMatrixMode(GL_MODELVIEW)
163
return True
164
165
@window.event
166
def on_draw():
167
"""Render the scene."""
168
window.clear()
169
glLoadIdentity()
170
171
# Setup camera
172
glTranslatef(0.0, 0.0, -5.0)
173
glRotatef(rotation_x, 1.0, 0.0, 0.0)
174
glRotatef(rotation_y, 0.0, 1.0, 0.0)
175
176
# Setup lighting
177
setup_lighting()
178
179
# Enable depth testing
180
glEnable(GL_DEPTH_TEST)
181
182
# Draw the model
183
visualization.draw(scene, lighting_enabled=True, textures_enabled=True)
184
185
# Animation variables
186
rotation_x = 0
187
rotation_y = 0
188
189
def update(dt):
190
"""Update animation."""
191
global rotation_y
192
rotation_y += 30 * dt # Rotate 30 degrees per second
193
194
# Start the rendering loop
195
pyglet.clock.schedule(update)
196
pyglet.app.run()
197
```
198
199
### Selective Material Rendering
200
201
```python
202
# Draw only specific materials
203
materials_to_draw = {
204
'metal': scene.materials['metal_material'],
205
'glass': scene.materials['glass_material']
206
}
207
visualization.draw_materials(materials_to_draw)
208
209
# Draw individual materials with custom settings
210
for name, material in scene.materials.items():
211
if 'transparent' in name:
212
# Disable lighting for transparent materials
213
visualization.draw_material(material, lighting_enabled=False)
214
else:
215
visualization.draw_material(material)
216
```
217
218
### Rendering Control
219
220
```python
221
# Disable textures for wireframe-like rendering
222
visualization.draw(scene, textures_enabled=False)
223
224
# Disable lighting for unlit rendering
225
visualization.draw(scene, lighting_enabled=False)
226
227
# Draw with back-face culling
228
for material in scene.materials.values():
229
visualization.draw_material(material, face=GL_FRONT)
230
```
231
232
### OpenGL State Management
233
234
The visualization module automatically manages OpenGL state:
235
236
**Enabled States:**
237
- `GL_CULL_FACE` - Back-face culling
238
- `GL_DEPTH_TEST` - Depth buffer testing
239
- `GL_LIGHTING` - When lighting_enabled=True
240
- `GL_TEXTURE_2D` - When textures are available
241
242
**Automatic Cleanup:**
243
- Client vertex array state (`GL_CLIENT_VERTEX_ARRAY_BIT`)
244
- Current OpenGL state (`GL_CURRENT_BIT`, `GL_ENABLE_BIT`, `GL_LIGHTING_BIT`)
245
246
### Error Handling
247
248
```python
249
try:
250
visualization.draw(scene)
251
except ValueError as e:
252
if "not supported by pyglet" in str(e):
253
print(f"Unsupported vertex format: {e}")
254
# Handle unsupported vertex format
255
else:
256
raise
257
```
258
259
Common issues:
260
- Unsupported vertex formats (e.g., `C3F_N3F_V3F`)
261
- Missing pyglet installation
262
- Texture loading failures
263
- OpenGL context issues
264
265
### Performance Considerations
266
267
**Optimization Tips:**
268
- Use vertex buffer objects (VBOs) for large models
269
- Batch materials with similar properties
270
- Minimize texture binding changes
271
- Use appropriate level-of-detail (LOD) for distant objects
272
- Consider frustum culling for complex scenes
273
274
**Memory Management:**
275
- Materials automatically cache OpenGL float arrays (`material.gl_floats`)
276
- Textures are loaded once and reused
277
- Vertex data is shared between materials when possible