Speed up FBX export of vertex colors with numpy #104454

Merged
Bastien Montagne merged 1 commits from Mysteryem/blender-addons:fbx_numpy_vertex_colors_pr_standalone into main 2023-03-06 15:30:14 +01:00
1 changed files with 22 additions and 12 deletions

View File

@ -1248,38 +1248,48 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
colors_type = scene_data.settings.colors_type
vcolnumber = 0 if colors_type == 'NONE' else len(me.color_attributes)
if vcolnumber:
def _coltuples_gen(raw_cols):
return zip(*(iter(raw_cols),) * 4)
color_prop_name = "color_srgb" if colors_type == 'SRGB' else "color"
# ByteColorAttribute color also gets returned by the API as single precision float
bl_lc_dtype = np.single
bl_lvi_dtype = np.uintc
fbx_lc_dtype = np.float64
fbx_lcidx_dtype = np.int32
t_lvi = None
for colindex, collayer in enumerate(me.color_attributes):
is_point = collayer.domain == "POINT"
vcollen = len(me.vertices if is_point else me.loops)
t_lc = array.array(data_types.ARRAY_FLOAT64, (0.0,)) * vcollen * 4
# Each rgba component is flattened in the array
t_lc = np.empty(vcollen * 4, dtype=bl_lc_dtype)
collayer.data.foreach_get(color_prop_name, t_lc)
lay_vcol = elem_data_single_int32(geom, b"LayerElementColor", colindex)
elem_data_single_int32(lay_vcol, b"Version", FBX_GEOMETRY_VCOLOR_VERSION)
elem_data_single_string_unicode(lay_vcol, b"Name", collayer.name)
elem_data_single_string(lay_vcol, b"MappingInformationType", b"ByPolygonVertex")
elem_data_single_string(lay_vcol, b"ReferenceInformationType", b"IndexToDirect")
col2idx = tuple(set(_coltuples_gen(t_lc)))
elem_data_single_float64_array(lay_vcol, b"Colors", chain(*col2idx)) # Flatten again...
# Use the fast uniqueness helper function since we don't care about sorting.
t_lc, col_indices = fast_first_axis_unique(t_lc.reshape(-1, 4), return_inverse=True)
col2idx = {col: idx for idx, col in enumerate(col2idx)}
col_indices = list(col2idx[c] for c in _coltuples_gen(t_lc))
if is_point:
# for "point" domain colors, we could directly emit them
# with a "ByVertex" mapping type, but some software does not
# properly understand that. So expand to full "ByPolygonVertex"
# index map.
col_indices = list((col_indices[c.vertex_index] for c in me.loops))
if t_lvi is None:
t_lvi = np.empty(len(me.loops), dtype=bl_lvi_dtype)
me.loops.foreach_get("vertex_index", t_lvi)
col_indices = col_indices[t_lvi]
t_lc = t_lc.astype(fbx_lc_dtype, copy=False)
col_indices = astype_view_signedness(col_indices, fbx_lcidx_dtype)
elem_data_single_float64_array(lay_vcol, b"Colors", t_lc)
elem_data_single_int32_array(lay_vcol, b"ColorIndex", col_indices)
del col2idx
del t_lc
del _coltuples_gen
del col_indices
del t_lvi
# Write UV layers.
# Note: LayerElementTexture is deprecated since FBX 2011 - luckily!