Speed up FBX export of shape keys with numpy #104452

Merged
Bastien Montagne merged 1 commits from Mysteryem/blender-addons:fbx_numpy_shape_keys_pr into main 2023-03-06 15:19:32 +01:00
Member

Use buffer matching the C type of the "co" property in foreach_get to avoid having to iterate and cast every single element in the C foreach_getset function.

Replace use of vcos_transformed_gen mesh transform helper with numpy version.

Only get cos of shape keys that are needed, since shape keys that are relative to themselves and have no other shape keys are relative to them can be skipped.

~7-12 times faster for shape keys that are entirely equal
~11-25 times faster for shape keys that are entirely different and not similar
~16-28 times faster for shape keys that are almost entirely different but similar

This patch does usually slightly change the exported file because the math for calculating the difference between a shape key and its relative key is done with float64 precision, matching the fbx export type. Beforehand, the difference would be calculated using mathutils.Vector which are single precision float (usually float32).

Because numpy.isclose is not symmetrical, this patch can also rarely result in a difference in which shape key cos are considered similar and are therefore not included in the export.
Consider the relative difference between 0.5 and 1.0:
If 1.0 is considered the reference value there is a 50% difference, but if 0.5 is considered the reference value there is a 100% difference.
math.isclose and fbx_utils.similar_values_iter always picks the value with greater magnitude as the reference value, whereas numpy.isclose picks the second argument as the reference value.
math.isclose(0.5, 1.0, rel_tol=0.5) => True
math.isclose(1.0, 0.5, rel_tol=0.5) => True
numpy.isclose(0.5, 1.0, rtol=0.5) => True
numpy.isclose(1.0, 0.5, rtol=0.5) => False
The relative key of each shape key is used as the reference value for numpy.isclose.


Whether geom_mat_co is set or None didn't make much difference to the total speedup, which is why the timing comparison in the commit message doesn't mention geom_mat_co.

The speedup around shape key weights is very minor. Without the use of accessing the numpy arrays through their underlying memoryview objects, the main loop would be slower since numpy arrays seem to be quite a bit slower to iterate and index one element at a time compared to Python arrays.

It might be possible to speed up the export of shape key weights by figuring out ahead of time all the indices of vertices that are needed for shape key weights so that each vertex is only ever indexed at most once, but this sounded very complicated and I don't think shape key weights typically get used much. I'd rather hope and wait for some way to quickly access vertex group weights, similar to foreach_get/set, to get added to the Python API.

This patch depends on
#104447
I wasn't sure if I should include its commit in this PR, I have included it for now.

Use buffer matching the C type of the "co" property in foreach_get to avoid having to iterate and cast every single element in the C foreach_getset function. Replace use of vcos_transformed_gen mesh transform helper with numpy version. Only get cos of shape keys that are needed, since shape keys that are relative to themselves and have no other shape keys are relative to them can be skipped. ~7-12 times faster for shape keys that are entirely equal ~11-25 times faster for shape keys that are entirely different and not similar ~16-28 times faster for shape keys that are almost entirely different but similar This patch does usually slightly change the exported file because the math for calculating the difference between a shape key and its relative key is done with float64 precision, matching the fbx export type. Beforehand, the difference would be calculated using mathutils.Vector which are single precision float (usually float32). Because numpy.isclose is not symmetrical, this patch can also rarely result in a difference in which shape key cos are considered similar and are therefore not included in the export. Consider the relative difference between 0.5 and 1.0: If 1.0 is considered the reference value there is a 50% difference, but if 0.5 is considered the reference value there is a 100% difference. math.isclose and fbx_utils.similar_values_iter always picks the value with greater magnitude as the reference value, whereas numpy.isclose picks the second argument as the reference value. math.isclose(0.5, 1.0, rel_tol=0.5) => True math.isclose(1.0, 0.5, rel_tol=0.5) => True numpy.isclose(0.5, 1.0, rtol=0.5) => True numpy.isclose(1.0, 0.5, rtol=0.5) => False The relative key of each shape key is used as the reference value for numpy.isclose. ----- Whether geom_mat_co is set or None didn't make much difference to the total speedup, which is why the timing comparison in the commit message doesn't mention geom_mat_co. The speedup around shape key weights is very minor. Without the use of accessing the numpy arrays through their underlying memoryview objects, the main loop would be slower since numpy arrays seem to be quite a bit slower to iterate and index one element at a time compared to Python arrays. It might be possible to speed up the export of shape key weights by figuring out ahead of time all the indices of vertices that are needed for shape key weights so that each vertex is only ever indexed at most once, but this sounded very complicated and I don't think shape key weights typically get used much. I'd rather hope and wait for some way to quickly access vertex group weights, similar to foreach_get/set, to get added to the Python API. This patch depends on https://projects.blender.org/blender/blender-addons/pulls/104447 I wasn't sure if I should include its commit in this PR, I have included it for now.
Thomas Barlow requested review from Bastien Montagne 2023-02-28 01:21:51 +01:00
Bastien Montagne force-pushed fbx_numpy_shape_keys_pr from 386c5f7cac to fb55abded3 2023-02-28 18:07:11 +01:00 Compare
Bastien Montagne force-pushed fbx_numpy_shape_keys_pr from fb55abded3 to 0a68da4c8e 2023-03-06 15:17:32 +01:00 Compare
Bastien Montagne merged commit 3e783620b8 into main 2023-03-06 15:19:32 +01:00
Bastien Montagne deleted branch fbx_numpy_shape_keys_pr 2023-03-06 15:19:33 +01:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender-addons#104452
No description provided.