0
# Materials and Textures
1
2
Material properties, texture management, and shader parameter access. PyAssimp provides comprehensive access to material systems including property queries, texture mapping, and material type identification with support for various shading models and material workflows.
3
4
## Capabilities
5
6
### Material Properties
7
8
Material property access through a specialized dictionary interface supporting semantic keys.
9
10
```python { .api }
11
class Material:
12
"""
13
Material definition with properties and textures.
14
15
Attributes:
16
- properties: PropertyGetter, material property dictionary with semantic access
17
"""
18
properties: PropertyGetter
19
20
class PropertyGetter(dict):
21
"""
22
Material property dictionary with semantic key support.
23
24
Supports both simple key access and semantic tuple keys (key, semantic_index).
25
Material properties are organized by property type and semantic meaning.
26
"""
27
def __getitem__(self, key):
28
"""
29
Access property by key or (key, semantic) tuple.
30
31
Parameters:
32
- key: str or tuple, property name or (name, semantic_index)
33
34
Returns:
35
Property value (type varies by property)
36
"""
37
38
def keys(self):
39
"""
40
Iterate over property keys.
41
42
Yields:
43
str: Property key names
44
"""
45
46
def items(self):
47
"""
48
Iterate over property key-value pairs.
49
50
Yields:
51
tuple: (key, value) pairs
52
"""
53
```
54
55
Usage examples:
56
57
```python
58
import pyassimp
59
60
scene = pyassimp.load("textured_model.obj")
61
62
for i, material in enumerate(scene.materials):
63
print(f"Material {i}:")
64
65
# Access all properties
66
for key, value in material.properties.items():
67
print(f" {key}: {value}")
68
69
# Access specific properties
70
properties = material.properties
71
72
# Common material properties
73
if 'diffuse' in properties:
74
diffuse_color = properties['diffuse']
75
print(f" Diffuse color: {diffuse_color}")
76
77
if 'specular' in properties:
78
specular_color = properties['specular']
79
print(f" Specular color: {specular_color}")
80
81
if 'shininess' in properties:
82
shininess = properties['shininess']
83
print(f" Shininess: {shininess}")
84
85
# Texture properties (using semantic indices)
86
try:
87
diffuse_texture = properties[('file', 1)] # Diffuse texture
88
print(f" Diffuse texture: {diffuse_texture}")
89
except KeyError:
90
pass
91
92
try:
93
normal_texture = properties[('file', 2)] # Normal map
94
print(f" Normal texture: {normal_texture}")
95
except KeyError:
96
pass
97
98
pyassimp.release(scene)
99
```
100
101
### Texture Data
102
103
Embedded texture data and texture information.
104
105
```python { .api }
106
class Texture:
107
"""
108
Embedded texture data.
109
110
Attributes:
111
- achformathint: str, format hint/extension (e.g., "jpg", "png")
112
- data: array, texture pixel data
113
- width: int, texture width in pixels
114
- height: int, texture height in pixels
115
"""
116
achformathint: str
117
data: array
118
width: int
119
height: int
120
```
121
122
Usage examples:
123
124
```python
125
import pyassimp
126
127
scene = pyassimp.load("model_with_embedded_textures.blend")
128
129
if scene.textures:
130
for i, texture in enumerate(scene.textures):
131
print(f"Embedded texture {i}:")
132
print(f" Format hint: {texture.achformathint}")
133
print(f" Dimensions: {texture.width}x{texture.height}")
134
print(f" Data size: {len(texture.data) if texture.data else 0}")
135
136
# Save embedded texture
137
if texture.data and texture.achformathint:
138
filename = f"texture_{i}.{texture.achformathint}"
139
# Note: texture.data contains pixel data that may need format conversion
140
print(f" Can be saved as: {filename}")
141
142
pyassimp.release(scene)
143
```
144
145
### Material Types and Properties
146
147
Common material property identification and texture type constants.
148
149
```python { .api }
150
# Texture type constants (from pyassimp.material)
151
aiTextureType_NONE = 0x0 # No texture
152
aiTextureType_DIFFUSE = 0x1 # Diffuse color texture
153
aiTextureType_SPECULAR = 0x2 # Specular color texture
154
aiTextureType_AMBIENT = 0x3 # Ambient color texture
155
aiTextureType_EMISSIVE = 0x4 # Emissive color texture
156
aiTextureType_HEIGHT = 0x5 # Height map
157
aiTextureType_NORMALS = 0x6 # Normal map
158
aiTextureType_SHININESS = 0x7 # Shininess map
159
aiTextureType_OPACITY = 0x8 # Opacity map
160
aiTextureType_DISPLACEMENT = 0x9 # Displacement map
161
aiTextureType_LIGHTMAP = 0xA # Light map
162
aiTextureType_REFLECTION = 0xB # Reflection map
163
aiTextureType_UNKNOWN = 0xC # Unknown texture type
164
```
165
166
Usage examples:
167
168
```python
169
import pyassimp
170
from pyassimp.material import *
171
172
def analyze_material_textures(material):
173
"""Analyze texture usage in a material."""
174
175
texture_types = {
176
'diffuse': aiTextureType_DIFFUSE,
177
'specular': aiTextureType_SPECULAR,
178
'normal': aiTextureType_NORMALS,
179
'height': aiTextureType_HEIGHT,
180
'opacity': aiTextureType_OPACITY,
181
'emissive': aiTextureType_EMISSIVE
182
}
183
184
found_textures = {}
185
186
for name, tex_type in texture_types.items():
187
try:
188
# Look for texture file property with semantic index
189
texture_path = material.properties[('file', tex_type)]
190
found_textures[name] = texture_path
191
except KeyError:
192
pass
193
194
return found_textures
195
196
# Usage
197
scene = pyassimp.load("complex_material.dae")
198
199
for i, material in enumerate(scene.materials):
200
print(f"Material {i} textures:")
201
textures = analyze_material_textures(material)
202
203
for tex_type, path in textures.items():
204
print(f" {tex_type}: {path}")
205
206
pyassimp.release(scene)
207
```
208
209
## Advanced Material Usage
210
211
### Material Property Extraction
212
213
```python
214
import pyassimp
215
216
def extract_material_info(material):
217
"""Extract common material properties."""
218
219
props = material.properties
220
material_info = {}
221
222
# Color properties
223
color_props = ['diffuse', 'specular', 'ambient', 'emissive']
224
for prop in color_props:
225
if prop in props:
226
material_info[prop + '_color'] = props[prop]
227
228
# Scalar properties
229
scalar_props = ['shininess', 'opacity', 'refracti']
230
for prop in scalar_props:
231
if prop in props:
232
material_info[prop] = props[prop]
233
234
# String properties
235
string_props = ['name']
236
for prop in string_props:
237
if prop in props:
238
material_info[prop] = props[prop]
239
240
# Texture paths
241
texture_semantics = {
242
'diffuse_map': 1,
243
'specular_map': 2,
244
'ambient_map': 3,
245
'emissive_map': 4,
246
'height_map': 5,
247
'normal_map': 6,
248
'shininess_map': 7,
249
'opacity_map': 8,
250
'displacement_map': 9,
251
'lightmap': 10,
252
'reflection_map': 11
253
}
254
255
for map_name, semantic in texture_semantics.items():
256
try:
257
texture_path = props[('file', semantic)]
258
material_info[map_name] = texture_path
259
except KeyError:
260
pass
261
262
return material_info
263
264
# Usage
265
scene = pyassimp.load("pbr_model.gltf")
266
267
for i, material in enumerate(scene.materials):
268
info = extract_material_info(material)
269
print(f"Material {i}:")
270
for key, value in info.items():
271
print(f" {key}: {value}")
272
273
pyassimp.release(scene)
274
```
275
276
### Material-Mesh Mapping
277
278
```python
279
import pyassimp
280
281
def create_material_mesh_mapping(scene):
282
"""Create mapping between materials and meshes that use them."""
283
284
material_usage = {}
285
286
for mat_idx in range(len(scene.materials)):
287
material_usage[mat_idx] = {
288
'material': scene.materials[mat_idx],
289
'meshes': []
290
}
291
292
for mesh_idx, mesh in enumerate(scene.meshes):
293
mat_idx = mesh.materialindex
294
if mat_idx < len(scene.materials):
295
material_usage[mat_idx]['meshes'].append({
296
'index': mesh_idx,
297
'mesh': mesh,
298
'vertex_count': len(mesh.vertices) if mesh.vertices else 0,
299
'face_count': len(mesh.faces) if mesh.faces else 0
300
})
301
302
return material_usage
303
304
# Usage
305
scene = pyassimp.load("multi_material_model.obj")
306
307
mapping = create_material_mesh_mapping(scene)
308
309
for mat_idx, info in mapping.items():
310
material = info['material']
311
meshes = info['meshes']
312
313
print(f"Material {mat_idx}: {len(meshes)} meshes")
314
315
# Show material properties
316
if 'diffuse' in material.properties:
317
print(f" Diffuse: {material.properties['diffuse']}")
318
319
# Show mesh usage
320
total_vertices = sum(mesh['vertex_count'] for mesh in meshes)
321
total_faces = sum(mesh['face_count'] for mesh in meshes)
322
print(f" Total vertices: {total_vertices}")
323
print(f" Total faces: {total_faces}")
324
325
pyassimp.release(scene)
326
```
327
328
### PBR Material Detection
329
330
```python
331
import pyassimp
332
333
def detect_pbr_workflow(material):
334
"""Detect if material uses PBR workflow and which type."""
335
336
props = material.properties
337
338
# Look for PBR-specific properties
339
pbr_indicators = {
340
'metallic_roughness': ['metallic', 'roughness'],
341
'specular_glossiness': ['specular', 'glossiness'],
342
'base_color': ['base_color', 'basecolor']
343
}
344
345
workflow = None
346
properties_found = {}
347
348
for workflow_name, prop_names in pbr_indicators.items():
349
found_props = []
350
for prop in prop_names:
351
if prop in props:
352
found_props.append(prop)
353
properties_found[prop] = props[prop]
354
355
if found_props:
356
workflow = workflow_name
357
break
358
359
# Look for PBR texture maps
360
pbr_textures = {}
361
pbr_texture_semantics = {
362
'basecolor_map': ('file', 1),
363
'metallic_map': ('file', 12), # Assuming extended semantics
364
'roughness_map': ('file', 13),
365
'normal_map': ('file', 6),
366
'occlusion_map': ('file', 14),
367
'emissive_map': ('file', 4)
368
}
369
370
for tex_name, (key, semantic) in pbr_texture_semantics.items():
371
try:
372
texture_path = props[(key, semantic)]
373
pbr_textures[tex_name] = texture_path
374
except KeyError:
375
continue
376
377
return {
378
'workflow': workflow,
379
'properties': properties_found,
380
'textures': pbr_textures
381
}
382
383
# Usage
384
scene = pyassimp.load("pbr_model.gltf")
385
386
for i, material in enumerate(scene.materials):
387
pbr_info = detect_pbr_workflow(material)
388
389
print(f"Material {i}:")
390
print(f" PBR workflow: {pbr_info['workflow']}")
391
print(f" Properties: {pbr_info['properties']}")
392
print(f" Textures: {pbr_info['textures']}")
393
394
pyassimp.release(scene)
395
```
396
397
### Texture Path Resolution
398
399
```python
400
import pyassimp
401
import os
402
403
def resolve_texture_paths(scene, model_directory):
404
"""Resolve relative texture paths to absolute paths."""
405
406
resolved_textures = {}
407
408
for mat_idx, material in enumerate(scene.materials):
409
material_textures = {}
410
411
# Get all texture properties
412
for key, value in material.properties.items():
413
if isinstance(key, tuple) and key[0] == 'file':
414
texture_path = value
415
416
# Resolve relative paths
417
if not os.path.isabs(texture_path):
418
resolved_path = os.path.join(model_directory, texture_path)
419
resolved_path = os.path.normpath(resolved_path)
420
else:
421
resolved_path = texture_path
422
423
# Check if file exists
424
exists = os.path.exists(resolved_path)
425
426
material_textures[key[1]] = {
427
'original_path': texture_path,
428
'resolved_path': resolved_path,
429
'exists': exists
430
}
431
432
if material_textures:
433
resolved_textures[mat_idx] = material_textures
434
435
return resolved_textures
436
437
# Usage
438
model_path = "models/house/house.obj"
439
model_dir = os.path.dirname(model_path)
440
441
scene = pyassimp.load(model_path)
442
texture_info = resolve_texture_paths(scene, model_dir)
443
444
for mat_idx, textures in texture_info.items():
445
print(f"Material {mat_idx} textures:")
446
for semantic, info in textures.items():
447
status = "✓" if info['exists'] else "✗"
448
print(f" Semantic {semantic}: {info['original_path']} → {info['resolved_path']} {status}")
449
450
pyassimp.release(scene)
451
```
452
453
## Material Property Reference
454
455
Common material properties you might encounter:
456
457
### Color Properties
458
- `diffuse`: Diffuse color (RGB or RGBA)
459
- `specular`: Specular color
460
- `ambient`: Ambient color
461
- `emissive`: Emissive/self-illumination color
462
- `transparent`: Transparency color
463
464
### Scalar Properties
465
- `shininess`: Specular shininess/power
466
- `opacity`: Material opacity (1.0 = opaque, 0.0 = transparent)
467
- `refracti`: Refractive index
468
- `reflectivity`: Reflectivity factor
469
470
### String Properties
471
- `name`: Material name
472
- `shadingm`: Shading model identifier
473
474
### Texture Properties (by semantic index)
475
- Semantic 1: Diffuse texture
476
- Semantic 2: Specular texture
477
- Semantic 3: Ambient texture
478
- Semantic 4: Emissive texture
479
- Semantic 5: Height map
480
- Semantic 6: Normal map
481
- Semantic 7: Shininess map
482
- Semantic 8: Opacity map
483
- Semantic 9: Displacement map
484
- Semantic 10: Light map
485
- Semantic 11: Reflection map
486
487
## Performance Considerations
488
489
1. **Property Access**: Use direct key lookup rather than iteration when possible
490
2. **Memory Usage**: Material properties are loaded into memory; large property sets increase RAM usage
491
3. **Texture Loading**: Embedded textures are loaded into memory; external textures are referenced by path
492
4. **Property Iteration**: Iterating over all properties can be slow for materials with many properties
493
5. **Semantic Indices**: Using semantic indices is more reliable than key names across different file formats