88from pxr import Gf , Tf , Usd , UsdGeom , UsdShade , Vt
99
1010from .data import ConversionData
11- from .material import store_dae_material_data , store_mesh_material_reference
11+ from .material import store_dae_material_data , store_mesh_material_reference , use_material_id
1212from .numpy import convert_face_indices_array , convert_matrix4d , convert_vec2f_array , convert_vec3f_array
1313
1414__all__ = ["convert_collada" ]
1515
1616
1717def convert_collada (prim : Usd .Prim , input_path : pathlib .Path , data : ConversionData ) -> Usd .Prim | None :
1818 try :
19- _collada = collada .Collada (str (input_path ))
19+ # Ignore broken references (e.g., missing lights, cameras) to allow parsing incomplete DAE files
20+ _collada = collada .Collada (str (input_path ), ignore = [collada .DaeError ])
2021
2122 # Store the material data from the DAE file.
2223 store_dae_material_data (input_path , _collada , data )
@@ -50,6 +51,7 @@ def _convert_mesh(
5051 prim : Usd .Prim ,
5152 name : str ,
5253 geometry : collada .geometry .Geometry ,
54+ node_materials : list [collada .scene .MaterialNode ] | None ,
5355 matrix : np .ndarray ,
5456 data : ConversionData ,
5557) -> Usd .Prim :
@@ -78,6 +80,12 @@ def _convert_mesh(
7880 all_vertices = geometry .primitives [0 ].vertex if hasattr (geometry .primitives [0 ], "vertex" ) else None
7981 unique_vertex_indices = []
8082
83+ # Whether to use material IDs for material identification.
84+ # If True, the material ID is used as the identifier.
85+ # If False, the material name is used as the identifier.
86+ dae_file_path = pathlib .Path (_collada .filename )
87+ _use_material_id = use_material_id (dae_file_path , data )
88+
8189 for primitive in geometry .primitives :
8290 primitive_type = type (primitive ).__name__
8391
@@ -105,10 +113,20 @@ def _convert_mesh(
105113
106114 face_offsets .append (len (face_vertex_counts ))
107115
108- # Get the material name and store it temporarily.
116+ # Get the material_id from the primitive.
117+ # If node_materials exists, we need to re-search for the material ID using 'primitive.material'.
118+ material_id = (
119+ next ((material .target .id for material in node_materials if material .symbol == primitive .material ), primitive .material )
120+ if node_materials
121+ else primitive .material
122+ )
123+
124+ # Retrieve and store the material name or material ID.
109125 # For primitives, the material ID is retrieved.
110- # The material name that matches the material ID is retrieved from the material list in _collada.materials.
111- material_name = next ((material .name for material in _collada .materials if material .id == primitive .material ), None )
126+ # The material name or ID that matches the 'material_id' is retrieved from the material list in _collada.materials.
127+ material_name = next (
128+ (material .id if _use_material_id else material .name for material in _collada .materials if material .id == material_id ), None
129+ )
112130 face_material_names .append (material_name )
113131
114132 # normals.
@@ -133,7 +151,21 @@ def _convert_mesh(
133151 if hasattr (primitive , "texcoordset" ) and len (primitive .texcoordset ) > 0 :
134152 uv_data = np .array (primitive .texcoordset [0 ], dtype = np .float32 ).reshape (- 1 , 2 )
135153 all_uvs_list .append (uv_data )
136- uv_indices = primitive .texcoord_index if hasattr (primitive , "texcoord_index" ) else np .arange (len (uv_data ), dtype = np .int32 )
154+
155+ uv_indices = (
156+ primitive .texcoord_indexset [0 ]
157+ if hasattr (primitive , "texcoord_indexset" ) and len (primitive .texcoord_indexset ) > 0
158+ else np .arange (len (uv_data ), dtype = np .int32 )
159+ )
160+
161+ # Flatten the UV indices array if needed (same as normal_index processing)
162+ if is_triangle_type :
163+ # Flatten 2D array more efficiently
164+ if isinstance (uv_indices , np .ndarray ) and uv_indices .ndim > 1 :
165+ uv_indices = uv_indices .ravel ()
166+ else : # Polylist or Polygons
167+ pass # uv_indices is already a 1D numpy array
168+
137169 uv_indices_array = np .array (uv_indices , dtype = np .int32 ) + current_uv_offset
138170 all_uv_indices_list .append (uv_indices_array )
139171 current_uv_offset += len (uv_data )
@@ -210,11 +242,10 @@ def _convert_mesh(
210242 geom_subset .GetFamilyNameAttr ().Set (UsdShade .Tokens .materialBind )
211243 subset_offset += face_offset
212244
213- # Stores the material names referenced by geometry. Each primitive can have its own material.
245+ # Stores the material names or IDs referenced by geometry. Each primitive can have its own material.
214246 # These will be allocated per single mesh or GeomSubset in USD.
215247 # Material binding is done on the Material layer, so no binding is done at this stage.
216248 if len (face_material_names ) > 0 :
217- dae_file_path = pathlib .Path (_collada .filename )
218249 store_mesh_material_reference (dae_file_path , usd_mesh .GetPrim ().GetName (), face_material_names , data )
219250
220251 # Convert the matrix to a Gf.Matrix4d.
@@ -253,7 +284,7 @@ def _traverse_scene(
253284 # Converts geometry to usd meshes.
254285 # If the geometry has no primitives, skip the conversion.
255286 # The name of the mesh to be created will be the geometry name in DAE.
256- _convert_mesh (_collada , prim , node .geometry .name , node .geometry , matrix , data )
287+ _convert_mesh (_collada , prim , node .geometry .name , node .geometry , node . materials , matrix , data )
257288
258289 if hasattr (node , "children" ) and node .children :
259290 for child in node .children :
0 commit comments