From f41472bfcfdaf80ef7ac9cd86938691740fa4a78 Mon Sep 17 00:00:00 2001 From: Thomas Barlow Date: Wed, 26 Apr 2023 22:53:13 +0100 Subject: [PATCH] FBX IO: Vertex position access with attributes Blender 3.5 moved vertex positions to a generic attribute. The old API still works for now, but is slower and may be removed in 4.0, so this patch updates FBX IO to use the new "position" attribute. This patch makes no changes to the import or export of FBX files. --- io_scene_fbx/export_fbx_bin.py | 14 ++++++-------- io_scene_fbx/import_fbx.py | 23 +++++++++-------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py index 8ab27449e..4bca25895 100644 --- a/io_scene_fbx/export_fbx_bin.py +++ b/io_scene_fbx/export_fbx_bin.py @@ -894,12 +894,10 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes): attributes = me.attributes # Vertex cos. - co_bl_dtype = np.single - co_fbx_dtype = np.float64 - t_co = np.empty(len(me.vertices) * 3, dtype=co_bl_dtype) - me.vertices.foreach_get("co", t_co) - elem_data_single_float64_array(geom, b"Vertices", vcos_transformed(t_co, geom_mat_co, co_fbx_dtype)) - del t_co + pos_fbx_dtype = np.float64 + t_pos = MESH_ATTRIBUTE_POSITION.to_ndarray(attributes) + elem_data_single_float64_array(geom, b"Vertices", vcos_transformed(t_pos, geom_mat_co, pos_fbx_dtype)) + del t_pos # Polygon indices. # @@ -2662,10 +2660,10 @@ def fbx_data_from_scene(scene, depsgraph, settings): # Get and cache only the cos that we need @cache def sk_cos(shape_key): - _cos = np.empty(len(me.vertices) * 3, dtype=co_bl_dtype) if shape_key == sk_base: - me.vertices.foreach_get("co", _cos) + _cos = MESH_ATTRIBUTE_POSITION.to_ndarray(me.attributes) else: + _cos = np.empty(len(me.vertices) * 3, dtype=co_bl_dtype) shape_key.data.foreach_get("co", _cos) return vcos_transformed(_cos, geom_mat_co, co_fbx_dtype) diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py index 316daa797..89f7814ec 100644 --- a/io_scene_fbx/import_fbx.py +++ b/io_scene_fbx/import_fbx.py @@ -1452,8 +1452,6 @@ def blen_read_geom(fbx_tmpl, fbx_obj, settings): fbx_polys = elem_prop_first(elem_find_first(fbx_obj, b'PolygonVertexIndex')) fbx_edges = elem_prop_first(elem_find_first(fbx_obj, b'Edges')) - bl_vcos_dtype = np.single - # The dtypes when empty don't matter, but are set to what the fbx arrays are expected to be. fbx_verts = parray_as_ndarray(fbx_verts) if fbx_verts else np.empty(0, dtype=data_types.ARRAY_FLOAT64) fbx_polys = parray_as_ndarray(fbx_polys) if fbx_polys else np.empty(0, dtype=data_types.ARRAY_INT32) @@ -1474,12 +1472,12 @@ def blen_read_geom(fbx_tmpl, fbx_obj, settings): if tot_verts: if geom_mat_co is not None: - fbx_verts = vcos_transformed(fbx_verts, geom_mat_co, bl_vcos_dtype) + fbx_verts = vcos_transformed(fbx_verts, geom_mat_co, MESH_ATTRIBUTE_POSITION.dtype) else: - fbx_verts = fbx_verts.astype(bl_vcos_dtype, copy=False) + fbx_verts = fbx_verts.astype(MESH_ATTRIBUTE_POSITION.dtype, copy=False) mesh.vertices.add(tot_verts) - mesh.vertices.foreach_set("co", fbx_verts.ravel()) + MESH_ATTRIBUTE_POSITION.foreach_set(attributes, fbx_verts.ravel()) if tot_loops: bl_loop_start_dtype = bl_loop_vertex_index_dtype = np.uintc @@ -1596,9 +1594,7 @@ def blen_read_shapes(fbx_tmpl, fbx_data, objects, me, scene): # No shape key data. Nothing to do. return - bl_vcos_dtype = np.single - me_vcos = np.empty(len(me.vertices) * 3, dtype=bl_vcos_dtype) - me.vertices.foreach_get("co", me_vcos) + me_vcos = MESH_ATTRIBUTE_POSITION.to_ndarray(me.attributes) me_vcos_vector_view = me_vcos.reshape(-1, 3) objects = list({node.bl_obj for node in objects}) @@ -3530,19 +3526,18 @@ def load(operator, context, filepath="", if fbx_obj.props[-1] == b'Mesh': mesh = fbx_item[1] - if decal_offset != 0.0: + num_verts = len(mesh.vertices) + if decal_offset != 0.0 and num_verts > 0: for material in mesh.materials: if material in material_decals: - num_verts = len(mesh.vertices) - blen_cos_dtype = blen_norm_dtype = np.single - vcos = np.empty(num_verts * 3, dtype=blen_cos_dtype) + blen_norm_dtype = np.single + vcos = MESH_ATTRIBUTE_POSITION.to_ndarray(mesh.attributes) vnorm = np.empty(num_verts * 3, dtype=blen_norm_dtype) - mesh.vertices.foreach_get("co", vcos) mesh.vertex_normals.foreach_get("vector", vnorm) vcos += vnorm * decal_offset - mesh.vertices.foreach_set("co", vcos) + MESH_ATTRIBUTE_POSITION.foreach_set(mesh.attributes, vcos) break for obj in (obj for obj in bpy.data.objects if obj.data == mesh): -- 2.30.2