WIP: FBX IO: Speed up shape key access using pointers #105126
@ -713,6 +713,8 @@ def _fast_mesh_shape_key_co_check():
|
||||
# The check has already been run and the result has been stored in _USE_FAST_SHAPE_KEY_CO_FOREACH_GETSET.
|
||||
return _USE_FAST_SHAPE_KEY_CO_FOREACH_GETSET
|
||||
|
||||
# Check that accessing a shape key's data through its pointer works, by creating a temporary mesh and adding a shape
|
||||
# key to it.
|
||||
tmp_mesh = None
|
||||
tmp_object = None
|
||||
try:
|
||||
@ -737,14 +739,15 @@ def _fast_mesh_shape_key_co_check():
|
||||
# The check is this function, so explicitly don't do the check.
|
||||
co_memory_as_array = _shape_key_co_memory_as_ndarray(shape_key, do_check=False)
|
||||
if co_memory_as_array is not None:
|
||||
# Immediately make a copy in case the `foreach_get` afterwards can cause the memory to be reallocated.
|
||||
# Immediately make a copy in the unlikely case the `foreach_get` call afterward can cause the memory to be
|
||||
# reallocated.
|
||||
co_array_from_memory = co_memory_as_array.copy()
|
||||
del co_memory_as_array
|
||||
# Check that the array created from the pointer has the exact same contents
|
||||
# as using foreach_get.
|
||||
co_array_check = np.empty(num_co * 3, dtype=co_dtype)
|
||||
shape_data.foreach_get("co", co_array_check)
|
||||
if np.array_equal(co_array_check, co_array_from_memory, equal_nan=True):
|
||||
co_array_from_foreach_get = np.empty(num_co * 3, dtype=co_dtype)
|
||||
shape_data.foreach_get("co", co_array_from_foreach_get)
|
||||
if np.array_equal(co_array_from_foreach_get, co_array_from_memory, equal_nan=True):
|
||||
_USE_FAST_SHAPE_KEY_CO_FOREACH_GETSET = True
|
||||
return True
|
||||
|
||||
@ -761,6 +764,9 @@ def _fast_mesh_shape_key_co_check():
|
||||
|
||||
|
||||
def fast_mesh_shape_key_co_foreach_get(shape_key, seq):
|
||||
"""
|
||||
Replacement for ShapeKey.data.foreach_get that accesses the shape key data's memory directly if possible.
|
||||
"""
|
||||
co_memory_as_array = _shape_key_co_memory_as_ndarray(shape_key)
|
||||
if co_memory_as_array is not None:
|
||||
seq[:] = co_memory_as_array
|
||||
@ -770,9 +776,10 @@ def fast_mesh_shape_key_co_foreach_get(shape_key, seq):
|
||||
|
||||
def fast_mesh_shape_key_dvcos_foreach_set(new_shape_key, dvcos, indices, mesh_positions_fallback_vector_view):
|
||||
"""
|
||||
FBX Shape key data are sparse vectors relative to the mesh, unlike Blender shape keys which are coordinates.
|
||||
Apply sparse FBX shape key vectors to a newly created shape key.
|
||||
|
||||
The newly created shape keys must have been created with `from_mix=False`, so that they match the mesh positions.
|
||||
The newly created shape key must have been created with `from_mix=False`, so that its coordinates match the mesh
|
||||
positions.
|
||||
"""
|
||||
co_memory_as_array = _shape_key_co_memory_as_ndarray(new_shape_key)
|
||||
if co_memory_as_array is not None:
|
||||
@ -782,6 +789,8 @@ def fast_mesh_shape_key_dvcos_foreach_set(new_shape_key, dvcos, indices, mesh_po
|
||||
# Memory has been set directly, so call .update().
|
||||
new_shape_key.data.update()
|
||||
else:
|
||||
# As a fallback, copy the mesh positions, apply the sparse vectors to that copy and then set all the shape key
|
||||
# coordinates to the modified copy of the mesh positions.
|
||||
shape_cos = mesh_positions_fallback_vector_view.copy()
|
||||
shape_cos[indices] += dvcos
|
||||
new_shape_key.data.foreach_set("co", shape_cos.ravel())
|
||||
|
Loading…
Reference in New Issue
Block a user