diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py index a3850aed8..784cfcc74 100644 --- a/io_scene_fbx/__init__.py +++ b/io_scene_fbx/__init__.py @@ -5,7 +5,7 @@ bl_info = { "name": "FBX format", "author": "Campbell Barton, Bastien Montagne, Jens Restemeier, @Mysteryem", - "version": (5, 10, 3), + "version": (5, 11, 0), "blender": (4, 1, 0), "location": "File > Import-Export", "description": "FBX IO meshes, UVs, vertex colors, materials, textures, cameras, lamps and actions", diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py index 2b384cae8..d5a9a1b48 100644 --- a/io_scene_fbx/export_fbx_bin.py +++ b/io_scene_fbx/export_fbx_bin.py @@ -1155,10 +1155,6 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes): # Loop normals. tspacenumber = 0 if write_normals: - # NOTE: ByVertice-IndexToDirect is not supported by the importer currently. - # XXX Official docs says normals should use IndexToDirect, - # but this does not seem well supported by apps currently... - normal_bl_dtype = np.single normal_fbx_dtype = np.float64 match me.normals_domain: @@ -1182,41 +1178,31 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes): t_normal = np.empty(len(normal_source) * 3, dtype=normal_bl_dtype) normal_source.foreach_get("vector", t_normal) t_normal = nors_transformed(t_normal, geom_mat_no, normal_fbx_dtype) - if 0: - normal_idx_fbx_dtype = np.int32 - lay_nor = elem_data_single_int32(geom, b"LayerElementNormal", 0) - elem_data_single_int32(lay_nor, b"Version", FBX_GEOMETRY_NORMAL_VERSION) - elem_data_single_string(lay_nor, b"Name", b"") - elem_data_single_string(lay_nor, b"MappingInformationType", normal_mapping) - elem_data_single_string(lay_nor, b"ReferenceInformationType", b"IndexToDirect") + normal_idx_fbx_dtype = np.int32 + lay_nor = elem_data_single_int32(geom, b"LayerElementNormal", 0) + elem_data_single_int32(lay_nor, b"Version", FBX_GEOMETRY_NORMAL_VERSION) + elem_data_single_string(lay_nor, b"Name", b"") + elem_data_single_string(lay_nor, b"MappingInformationType", normal_mapping) + # FBX SDK documentation says that normals should use IndexToDirect. + elem_data_single_string(lay_nor, b"ReferenceInformationType", b"IndexToDirect") - # Tuple of unique sorted normals and then the index in the unique sorted normals of each normal in t_normal. - # Since we don't care about how the normals are sorted, only that they're unique, we can use the fast unique - # helper function. - t_normal, t_normal_idx = fast_first_axis_unique(t_normal.reshape(-1, 3), return_inverse=True) + # Tuple of unique sorted normals and then the index in the unique sorted normals of each normal in t_normal. + # Since we don't care about how the normals are sorted, only that they're unique, we can use the fast unique + # helper function. + t_normal, t_normal_idx = fast_first_axis_unique(t_normal.reshape(-1, 3), return_inverse=True) - # Convert to the type for fbx - t_normal_idx = astype_view_signedness(t_normal_idx, normal_idx_fbx_dtype) + # Convert to the type for fbx + t_normal_idx = astype_view_signedness(t_normal_idx, normal_idx_fbx_dtype) - elem_data_single_float64_array(lay_nor, b"Normals", t_normal) - # Normal weights, no idea what it is. - # t_normal_w = np.zeros(len(t_normal), dtype=np.float64) - # elem_data_single_float64_array(lay_nor, b"NormalsW", t_normal_w) + elem_data_single_float64_array(lay_nor, b"Normals", t_normal) + # Normal weights, no idea what it is. + # t_normal_w = np.zeros(len(t_normal), dtype=np.float64) + # elem_data_single_float64_array(lay_nor, b"NormalsW", t_normal_w) - elem_data_single_int32_array(lay_nor, b"NormalsIndex", t_normal_idx) + elem_data_single_int32_array(lay_nor, b"NormalsIndex", t_normal_idx) - del t_normal_idx - # del t_normal_w - else: - lay_nor = elem_data_single_int32(geom, b"LayerElementNormal", 0) - elem_data_single_int32(lay_nor, b"Version", FBX_GEOMETRY_NORMAL_VERSION) - elem_data_single_string(lay_nor, b"Name", b"") - elem_data_single_string(lay_nor, b"MappingInformationType", normal_mapping) - elem_data_single_string(lay_nor, b"ReferenceInformationType", b"Direct") - elem_data_single_float64_array(lay_nor, b"Normals", t_normal) - # Normal weights, no idea what it is. - # t_normal = np.zeros(len(me.loops), dtype=np.float64) - # elem_data_single_float64_array(lay_nor, b"NormalsW", t_normal) + del t_normal_idx + # del t_normal_w del t_normal # tspace diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py index 8a50280d2..6152c3804 100644 --- a/io_scene_fbx/import_fbx.py +++ b/io_scene_fbx/import_fbx.py @@ -1398,7 +1398,18 @@ def blen_read_geom_array_mapped_vert( xform=None, quiet=False, ): if fbx_layer_mapping == b'ByVertice': - if fbx_layer_ref == b'Direct': + if fbx_layer_ref == b'IndexToDirect': + # XXX Looks like we often get no fbx_layer_index in this case, shall not happen but happens... + # We fallback to 'Direct' mapping in this case. + #~ assert(fbx_layer_index is not None) + if fbx_layer_index is None: + blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride, + item_size, descr, xform) + else: + blen_read_geom_array_foreach_set_indexed(blen_data, blen_attr, blen_dtype, fbx_layer_data, + fbx_layer_index, stride, item_size, descr, xform) + return True + elif fbx_layer_ref == b'Direct': assert(fbx_layer_index is None) blen_read_geom_array_foreach_set_direct(blen_data, blen_attr, blen_dtype, fbx_layer_data, stride, item_size, descr, xform) @@ -1754,8 +1765,6 @@ def blen_read_geom_layer_normal(fbx_obj, mesh, xform=None): loop_normals = np.repeat(bdata, poly_loop_totals, axis=0) mesh.attributes["temp_custom_normals"].data.foreach_set("vector", loop_normals.ravel()) elif blen_data_type == "Vertices": - # Note: Currently unreachable because `blen_read_geom_array_mapped_polyloop` covers all the supported - # import cases covered by `blen_read_geom_array_mapped_vert`. # We have to copy vnors to lnors! Far from elegant, but simple. loop_vertex_indices = MESH_ATTRIBUTE_CORNER_VERT.to_ndarray(mesh.attributes) mesh.attributes["temp_custom_normals"].data.foreach_set("vector", bdata[loop_vertex_indices].ravel())