glTF exporter: manage delta transform animation

This commit is contained in:
Julien Duroure 2022-09-19 09:24:35 +02:00
parent b9c0e2878e
commit 58db76bcc6
4 changed files with 65 additions and 24 deletions

View File

@ -4,7 +4,7 @@
bl_info = {
'name': 'glTF 2.0 format',
'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
"version": (3, 4, 15),
"version": (3, 4, 16),
'blender': (3, 3, 0),
'location': 'File > Import-Export',
'description': 'Import-Export as glTF 2.0',

View File

@ -15,20 +15,33 @@ def get_target_object_path(data_path: str) -> str:
return ""
return path_split[0]
def get_rotation_modes(target_property: str) -> str:
def get_rotation_modes(target_property: str):
"""Retrieve rotation modes based on target_property"""
if target_property == "rotation_euler":
return True, False, ["XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"]
return True, ["XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"]
elif target_property == "delta_rotation_euler":
return True, True, ["XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"]
return True, ["XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"]
elif target_property == "rotation_quaternion":
return True, False, ["QUATERNION"]
return True, ["QUATERNION"]
elif target_property == "delta_rotation_quaternion":
return True, True, ["QUATERNION"]
return True, ["QUATERNION"]
elif target_property in ["rotation_axis_angle"]:
return True, False, ["AXIS_ANGLE"]
return True, ["AXIS_ANGLE"]
else:
return False, False, []
return False, []
def is_location(target_property):
return "location" in target_property
def is_rotation(target_property):
return "rotation" in target_property
def is_scale(target_property):
return "scale" in target_property
def get_delta_modes(target_property: str) -> str:
"""Retrieve location based on target_property"""
return target_property.startswith("delta_")
def is_bone_anim_channel(data_path: str) -> bool:
return data_path[:10] == "pose.bones"

View File

@ -4,7 +4,7 @@
import bpy
import typing
from ..com.gltf2_blender_data_path import get_target_object_path, get_target_property_name, get_rotation_modes
from ..com.gltf2_blender_data_path import get_target_object_path, get_target_property_name, get_rotation_modes, get_delta_modes, is_location, is_rotation, is_scale
from io_scene_gltf2.io.com import gltf2_io
from io_scene_gltf2.io.com import gltf2_io_debug
from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached
@ -364,6 +364,8 @@ def __get_channel_groups(blender_action: bpy.types.Action, blender_object: bpy.t
targets = {}
multiple_rotation_mode_detected = False
delta_rotation_detection = [False, False] # Normal / Delta
delta_location_detection = [False, False] # Normal / Delta
delta_scale_detection = [False, False] # Normal / Delta
for fcurve in blender_action.fcurves:
# In some invalid files, channel hasn't any keyframes ... this channel need to be ignored
if len(fcurve.keyframe_points) == 0:
@ -405,24 +407,46 @@ def __get_channel_groups(blender_action: bpy.types.Action, blender_object: bpy.t
# Detect that object or bone are not multiple keyed for euler and quaternion
# Keep only the current rotation mode used by object
rotation, delta, rotation_modes = get_rotation_modes(target_property)
rotation, rotation_modes = get_rotation_modes(target_property)
delta = get_delta_modes(target_property)
# Delta rotation management
if delta is False:
if delta_rotation_detection[1] is True: # normal rotation coming, but delta is already present
multiple_rotation_mode_detected = True
continue
delta_rotation_detection[0] = True
else:
if delta_rotation_detection[0] is True: # delta rotation coming, but normal is already present
multiple_rotation_mode_detected = True
continue
delta_rotation_detection[1] = True
if is_rotation(target_property) :
if delta is False:
if delta_rotation_detection[1] is True: # normal rotation coming, but delta is already present
continue
delta_rotation_detection[0] = True
else:
if delta_rotation_detection[0] is True: # delta rotation coming, but normal is already present
continue
delta_rotation_detection[1] = True
if rotation and target.rotation_mode not in rotation_modes:
multiple_rotation_mode_detected = True
continue
if rotation and target.rotation_mode not in rotation_modes:
multiple_rotation_mode_detected = True
continue
# Delta location management
if is_location(target_property):
if delta is False:
if delta_location_detection[1] is True: # normal location coming, but delta is already present
continue
delta_location_detection[0] = True
else:
if delta_location_detection[0] is True: # delta location coming, but normal is already present
continue
delta_location_detection[1] = True
# Delta scale management
if is_scale(target_property):
if delta is False:
if delta_scale_detection[1] is True: # normal scale coming, but delta is already present
continue
delta_scale_detection[0] = True
else:
if delta_scale_detection[0] is True: # delta scale coming, but normal is already present
continue
delta_scale_detection[1] = True
# group channels by target object and affected property of the target
target_properties = targets.get(target, {})

View File

@ -45,6 +45,7 @@ class Keyframe:
length = {
"delta_location": 3,
"delta_rotation_euler": 3,
"delta_scale": 3,
"location": 3,
"rotation_axis_angle": 4,
"rotation_euler": 3,
@ -367,7 +368,10 @@ def gather_keyframes(blender_obj_uuid: str,
"rotation_axis_angle": [rot.to_axis_angle()[1], rot.to_axis_angle()[0][0], rot.to_axis_angle()[0][1], rot.to_axis_angle()[0][2]],
"rotation_euler": rot.to_euler(),
"rotation_quaternion": rot,
"scale": sca
"scale": sca,
"delta_location": trans,
"delta_rotation_euler": rot.to_euler(),
"delta_scale": sca
}[target]
else:
key.value = get_sk_driver_values(driver_obj_uuid, frame, channels, export_settings)