@@ -107,8 +107,8 @@ def load(self, scene, file=None):
107
107
self .load_images ()
108
108
self .load_samplers ()
109
109
self .load_textures ()
110
- self .load_meshes ()
111
110
self .load_materials ()
111
+ self .load_meshes ()
112
112
self .load_nodes ()
113
113
114
114
self .scene .calc_scene_bbox ()
@@ -170,10 +170,12 @@ def load_textures(self):
170
170
self .textures .append (mt )
171
171
172
172
def load_meshes (self ):
173
- for mesh in self .meta .meshes :
174
- m = mesh .load ()
175
- self .meshes .append (m )
176
- self .scene .meshes .append (m )
173
+ for meta_mesh in self .meta .meshes :
174
+ # Returns a list of meshes
175
+ meshes = meta_mesh .load (self .materials )
176
+ self .meshes .append (meshes )
177
+ for m in meshes :
178
+ self .scene .meshes .append (m )
177
179
178
180
def load_materials (self ):
179
181
# Create material objects
@@ -187,11 +189,6 @@ def load_materials(self):
187
189
self .materials .append (m )
188
190
self .scene .materials .append (m )
189
191
190
- # Map to meshes
191
- for i , mesh in enumerate (self .meta .meshes ):
192
- if mesh .primitives [0 ].material is not None :
193
- self .meshes [i ].material = self .materials [mesh .primitives [0 ].material ]
194
-
195
192
def load_nodes (self ):
196
193
# Start with root nodes in the scene
197
194
for node_id in self .meta .scenes [0 ].nodes :
@@ -207,7 +204,14 @@ def load_node(self, meta, parent=None):
207
204
node .matrix = Matrix44 (value = meta .matrix )
208
205
209
206
if meta .mesh is not None :
210
- node .mesh = self .meshes [meta .mesh ]
207
+ # Since we split up meshes with multiple primitives, this can be a list
208
+ # If only one mesh we set it on the node as normal
209
+ if len (self .meshes [meta .mesh ]) == 1 :
210
+ node .mesh = self .meshes [meta .mesh ][0 ]
211
+ # If multiple meshes we add them as new child node
212
+ elif len (self .meshes [meta .mesh ]) > 1 :
213
+ for mesh in self .meshes [meta .mesh ]:
214
+ node .add_child (Node (mesh = mesh ))
211
215
212
216
if meta .camera is not None :
213
217
# FIXME: Use a proper camera class
@@ -345,9 +349,7 @@ def __init__(self, data):
345
349
self .name = data .get ('name' )
346
350
self .primitives = [Primitives (p ) for p in data .get ('primitives' )]
347
351
348
- def load (self ):
349
- self .prepare_attrib_mapping ()
350
-
352
+ def load (self , materials ):
351
353
name_map = {
352
354
'POSITION' : 'in_position' ,
353
355
'NORMAL' : 'in_normal' ,
@@ -358,48 +360,58 @@ def load(self):
358
360
'COLOR_0' : 'in_color0' ,
359
361
}
360
362
361
- vbos = self .prepare_attrib_mapping ()
362
- vao = VAO (self .name , mode = self .primitives [0 ].mode or GL .GL_TRIANGLES )
363
+ meshes = []
363
364
364
- # Index buffer
365
- component_type , index_vbo = self .load_indices ()
366
- if index_vbo :
367
- vao .set_element_buffer (component_type .value , index_vbo )
365
+ # Read all primitives as separate meshes for now
366
+ # According to the spec they can have different materials and vertex format
367
+ for primitive in self .primitives :
368
368
369
- attributes = {}
369
+ vao = VAO ( self . name , mode = primitive . mode or GL . GL_TRIANGLES )
370
370
371
- for vbo_info in vbos :
372
- vbo = vbo_info .create ()
373
- vao .add_array_buffer (vbo_info .component_type .value , vbo )
371
+ # Index buffer
372
+ component_type , index_vbo = self .load_indices (primitive )
373
+ if index_vbo :
374
+ vao .set_element_buffer (component_type .value , index_vbo )
374
375
375
- for attr in vbo_info .attributes :
376
- vao .map_buffer (vbo , name_map [attr [0 ]], attr [1 ])
377
- attributes [attr [0 ]] = {
378
- 'name' : name_map [attr [0 ]],
379
- 'components' : attr [1 ],
380
- 'type' : vbo_info .component_type .value ,
381
- }
376
+ attributes = {}
382
377
383
- vao . build ( )
378
+ vbos = self . prepare_attrib_mapping ( primitive )
384
379
385
- bbox_min , bbox_max = self .get_bbox ()
386
- return Mesh (
387
- self .name , vao = vao , attributes = attributes ,
388
- bbox_min = bbox_min , bbox_max = bbox_max ,
389
- )
380
+ for vbo_info in vbos :
381
+ vbo = vbo_info .create ()
382
+ vao .add_array_buffer (vbo_info .component_type .value , vbo )
383
+
384
+ for attr in vbo_info .attributes :
385
+ vao .map_buffer (vbo , name_map [attr [0 ]], attr [1 ])
386
+ attributes [attr [0 ]] = {
387
+ 'name' : name_map [attr [0 ]],
388
+ 'components' : attr [1 ],
389
+ 'type' : vbo_info .component_type .value ,
390
+ }
391
+
392
+ vao .build ()
393
+
394
+ bbox_min , bbox_max = self .get_bbox (primitive )
395
+ meshes .append (Mesh (
396
+ self .name , vao = vao , attributes = attributes ,
397
+ material = materials [primitive .material ],
398
+ bbox_min = bbox_min , bbox_max = bbox_max ,
399
+ ))
400
+
401
+ return meshes
390
402
391
- def load_indices (self ):
392
- """Loads the index buffer / polygon list"""
393
- if getattr (self . primitives [ 0 ] , "indices" ) is None :
403
+ def load_indices (self , primitive ):
404
+ """Loads the index buffer / polygon list for a primitive """
405
+ if getattr (primitive , "indices" ) is None :
394
406
return None , None
395
407
396
- _ , component_type , vbo = self . primitives [ 0 ] .indices .read (target = GL .GL_ELEMENT_ARRAY_BUFFER )
408
+ _ , component_type , vbo = primitive .indices .read (target = GL .GL_ELEMENT_ARRAY_BUFFER )
397
409
return component_type , vbo
398
410
399
- def prepare_attrib_mapping (self ):
411
+ def prepare_attrib_mapping (self , primitive ):
412
+ """Pre-parse buffer mappings for each VBO to detect interleaved data for a primitive"""
400
413
buffer_info = []
401
- """Pre-parse buffer mappings for each VBO to detect interleaved data"""
402
- for name , accessor in self .primitives [0 ].attributes .items ():
414
+ for name , accessor in primitive .attributes .items ():
403
415
info = VBOInfo (* accessor .info (target = GL .GL_ARRAY_BUFFER ))
404
416
info .attributes .append ((name , info .components ))
405
417
@@ -412,9 +424,9 @@ def prepare_attrib_mapping(self):
412
424
413
425
return buffer_info
414
426
415
- def get_bbox (self ):
427
+ def get_bbox (self , primitive ):
416
428
"""Get the bounding box for the mesh"""
417
- accessor = self . primitives [ 0 ] .attributes .get ('POSITION' )
429
+ accessor = primitive .attributes .get ('POSITION' )
418
430
return accessor .min , accessor .max
419
431
420
432
@@ -610,7 +622,8 @@ def is_resource_node(self):
610
622
class GLTFMaterial :
611
623
def __init__ (self , data ):
612
624
self .name = data .get ('name' )
613
- self .doubleSided = data .get ('doubleSided' ) or False
625
+ # Defaults to true if not defined
626
+ self .doubleSided = data .get ('doubleSided' ) or True
614
627
615
628
pbr = data ['pbrMetallicRoughness' ]
616
629
self .baseColorFactor = pbr .get ('baseColorFactor' )
0 commit comments