glTF exporter: performance: huge speedup when exporting using sample animations
This commit is contained in:
parent
14f1c99e96
commit
8d9e3c94af
|
@ -15,7 +15,7 @@
|
|||
bl_info = {
|
||||
'name': 'glTF 2.0 format',
|
||||
'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
|
||||
"version": (0, 9, 62),
|
||||
"version": (0, 9, 63),
|
||||
'blender': (2, 81, 6),
|
||||
'location': 'File > Import-Export',
|
||||
'description': 'Import-Export as glTF 2.0',
|
||||
|
|
|
@ -16,7 +16,7 @@ import bpy
|
|||
import mathutils
|
||||
import typing
|
||||
|
||||
from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached
|
||||
from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached, bonecache
|
||||
from io_scene_gltf2.blender.com import gltf2_blender_math
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_get
|
||||
from io_scene_gltf2.blender.exp import gltf2_blender_extract
|
||||
|
@ -111,6 +111,47 @@ class Keyframe:
|
|||
self.__out_tangent = self.__set_indexed(value)
|
||||
|
||||
|
||||
|
||||
@bonecache
|
||||
def get_bone_matrix(blender_object_if_armature: typing.Optional[bpy.types.Object],
|
||||
channels: typing.Tuple[bpy.types.FCurve],
|
||||
bake_bone: typing.Union[str, None],
|
||||
bake_channel: typing.Union[str, None],
|
||||
bake_range_start,
|
||||
bake_range_end,
|
||||
action_name: str,
|
||||
current_frame: int,
|
||||
step: int
|
||||
):
|
||||
|
||||
data = {}
|
||||
|
||||
if bake_bone is None:
|
||||
# Find the start and end of the whole action group
|
||||
ranges = [channel.range() for channel in channels]
|
||||
|
||||
start_frame = min([channel.range()[0] for channel in channels])
|
||||
end_frame = max([channel.range()[1] for channel in channels])
|
||||
else:
|
||||
start_frame = bake_range_start
|
||||
end_frame = bake_range_end
|
||||
|
||||
frame = start_frame
|
||||
while frame <= end_frame:
|
||||
data[frame] = {}
|
||||
# we need to bake in the constraints
|
||||
bpy.context.scene.frame_set(frame)
|
||||
for pbone in blender_object_if_armature.pose.bones:
|
||||
if bake_bone is None:
|
||||
matrix = pbone.matrix_basis
|
||||
else:
|
||||
matrix = pbone.matrix
|
||||
matrix = blender_object_if_armature.convert_space(pose_bone=pbone, matrix=matrix, from_space='POSE', to_space='LOCAL')
|
||||
data[frame][pbone.name] = matrix
|
||||
frame += step
|
||||
|
||||
return data
|
||||
|
||||
# cache for performance reasons
|
||||
@cached
|
||||
def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Object],
|
||||
|
@ -154,14 +195,20 @@ def gather_keyframes(blender_object_if_armature: typing.Optional[bpy.types.Objec
|
|||
while frame <= end_frame:
|
||||
key = Keyframe(channels, frame, bake_channel)
|
||||
if isinstance(pose_bone_if_armature, bpy.types.PoseBone):
|
||||
# we need to bake in the constraints
|
||||
bpy.context.scene.frame_set(frame)
|
||||
if bake_bone is None:
|
||||
trans, rot, scale = pose_bone_if_armature.matrix_basis.decompose()
|
||||
else:
|
||||
matrix = pose_bone_if_armature.matrix
|
||||
new_matrix = blender_object_if_armature.convert_space(pose_bone=pose_bone_if_armature, matrix=matrix, from_space='POSE', to_space='LOCAL')
|
||||
trans, rot, scale = new_matrix.decompose()
|
||||
|
||||
mat = get_bone_matrix(
|
||||
blender_object_if_armature,
|
||||
channels,
|
||||
bake_bone,
|
||||
bake_channel,
|
||||
bake_range_start,
|
||||
bake_range_end,
|
||||
action_name,
|
||||
frame,
|
||||
step
|
||||
)
|
||||
trans, rot, scale = mat.decompose()
|
||||
|
||||
if bake_channel is None:
|
||||
target_property = channels[0].data_path.split('.')[-1]
|
||||
else:
|
||||
|
|
|
@ -65,6 +65,27 @@ def cached(func):
|
|||
return result
|
||||
return wrapper_cached
|
||||
|
||||
def bonecache(func):
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapper_bonecache(*args, **kwargs):
|
||||
if args[2] is None:
|
||||
pose_bone_if_armature = gltf2_blender_get.get_object_from_datapath(args[0],
|
||||
args[1][0].data_path)
|
||||
else:
|
||||
pose_bone_if_armature = args[0].pose.bones[args[2]]
|
||||
|
||||
if not hasattr(func, "__current_action_name"):
|
||||
func.__current_action_name = None
|
||||
func.__bonecache = {}
|
||||
if args[6] != func.__current_action_name:
|
||||
result = func(*args)
|
||||
func.__bonecache = result
|
||||
func.__current_action_name = args[6]
|
||||
return result[args[7]][pose_bone_if_armature.name]
|
||||
else:
|
||||
return func.__bonecache[args[7]][pose_bone_if_armature.name]
|
||||
return wrapper_bonecache
|
||||
|
||||
# TODO: replace "cached" with "unique" in all cases where the caching is functional and not only for performance reasons
|
||||
call_or_fetch = cached
|
||||
|
|
Loading…
Reference in New Issue