@@ -107,8 +107,8 @@ def load(self, scene, file=None):
107107 self .load_images ()
108108 self .load_samplers ()
109109 self .load_textures ()
110- self .load_meshes ()
111110 self .load_materials ()
111+ self .load_meshes ()
112112 self .load_nodes ()
113113
114114 self .scene .calc_scene_bbox ()
@@ -170,10 +170,12 @@ def load_textures(self):
170170 self .textures .append (mt )
171171
172172 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 )
177179
178180 def load_materials (self ):
179181 # Create material objects
@@ -187,11 +189,6 @@ def load_materials(self):
187189 self .materials .append (m )
188190 self .scene .materials .append (m )
189191
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-
195192 def load_nodes (self ):
196193 # Start with root nodes in the scene
197194 for node_id in self .meta .scenes [0 ].nodes :
@@ -207,7 +204,14 @@ def load_node(self, meta, parent=None):
207204 node .matrix = Matrix44 (value = meta .matrix )
208205
209206 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 ))
211215
212216 if meta .camera is not None :
213217 # FIXME: Use a proper camera class
@@ -345,9 +349,7 @@ def __init__(self, data):
345349 self .name = data .get ('name' )
346350 self .primitives = [Primitives (p ) for p in data .get ('primitives' )]
347351
348- def load (self ):
349- self .prepare_attrib_mapping ()
350-
352+ def load (self , materials ):
351353 name_map = {
352354 'POSITION' : 'in_position' ,
353355 'NORMAL' : 'in_normal' ,
@@ -358,48 +360,58 @@ def load(self):
358360 'COLOR_0' : 'in_color0' ,
359361 }
360362
361- vbos = self .prepare_attrib_mapping ()
362- vao = VAO (self .name , mode = self .primitives [0 ].mode or GL .GL_TRIANGLES )
363+ meshes = []
363364
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 :
368368
369- attributes = {}
369+ vao = VAO ( self . name , mode = primitive . mode or GL . GL_TRIANGLES )
370370
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 )
374375
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 = {}
382377
383- vao . build ( )
378+ vbos = self . prepare_attrib_mapping ( primitive )
384379
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
390402
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 :
394406 return None , None
395407
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 )
397409 return component_type , vbo
398410
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"""
400413 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 ():
403415 info = VBOInfo (* accessor .info (target = GL .GL_ARRAY_BUFFER ))
404416 info .attributes .append ((name , info .components ))
405417
@@ -412,9 +424,9 @@ def prepare_attrib_mapping(self):
412424
413425 return buffer_info
414426
415- def get_bbox (self ):
427+ def get_bbox (self , primitive ):
416428 """Get the bounding box for the mesh"""
417- accessor = self . primitives [ 0 ] .attributes .get ('POSITION' )
429+ accessor = primitive .attributes .get ('POSITION' )
418430 return accessor .min , accessor .max
419431
420432
@@ -610,7 +622,8 @@ def is_resource_node(self):
610622class GLTFMaterial :
611623 def __init__ (self , data ):
612624 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
614627
615628 pbr = data ['pbrMetallicRoughness' ]
616629 self .baseColorFactor = pbr .get ('baseColorFactor' )
0 commit comments