diff --git a/korman/exporter/animation.py b/korman/exporter/animation.py index 0325805..0934de1 100644 --- a/korman/exporter/animation.py +++ b/korman/exporter/animation.py @@ -41,19 +41,19 @@ class AnimationConverter: return tm def make_pos_controller(self, fcurves, default_xform): - pos_curves = (i for i in fcurves if i.data_path == "location" and i.keyframe_points) + pos_curves = [i for i in fcurves if i.data_path == "location" and i.keyframe_points] keyframes, bez_chans = self._process_keyframes(pos_curves) if not keyframes: return None # At one point, I had some... insanity here to try to crush bezier channels and hand off to # blah blah blah... As it turns out, point3 keyframe's tangents are vector3s :) - ctrl = self._make_point3_controller(keyframes, bez_chans, default_xform.to_translation()) + ctrl = self._make_point3_controller(pos_curves, keyframes, bez_chans, default_xform.to_translation()) return ctrl def make_rot_controller(self, fcurves, default_xform): # TODO: support rotation_quaternion - rot_curves = (i for i in fcurves if i.data_path == "rotation_euler" and i.keyframe_points) + rot_curves = [i for i in fcurves if i.data_path == "rotation_euler" and i.keyframe_points] keyframes, bez_chans = self._process_keyframes(rot_curves) if not keyframes: return None @@ -61,27 +61,27 @@ class AnimationConverter: # Ugh. Unfortunately, it appears Blender's default interpolation is bezier. So who knows if # many users will actually see the benefit here? Makes me sad. if bez_chans: - ctrl = self._make_scalar_controller(keyframes, bez_chans, default_xform.to_euler("XYZ")) + ctrl = self._make_scalar_controller(rot_curves, keyframes, bez_chans, default_xform.to_euler()) else: - ctrl = self._make_quat_controller(keyframes, default_xform.to_euler("XYZ")) + ctrl = self._make_quat_controller(rot_curves, keyframes, default_xform.to_euler()) return ctrl def make_scale_controller(self, fcurves, default_xform): - scale_curves = (i for i in fcurves if i.data_path == "scale" and i.keyframe_points) + scale_curves = [i for i in fcurves if i.data_path == "scale" and i.keyframe_points] keyframes, bez_chans = self._process_keyframes(scale_curves) if not keyframes: return None # There is no such thing as a compound scale controller... in Plasma, anyway. - ctrl = self._make_scale_value_controller(keyframes, bez_chans, default_xform) + ctrl = self._make_scale_value_controller(scale_curves, keyframes, bez_chans, default_xform) return ctrl - def _make_point3_controller(self, keyframes, bezier, default_xform): + def _make_point3_controller(self, fcurves, keyframes, bezier, default_xform): ctrl = plLeafController() subctrls = ("X", "Y", "Z") keyframe_type = hsKeyFrame.kBezPoint3KeyFrame if bezier else hsKeyFrame.kPoint3KeyFrame exported_frames = [] - last_xform = [default_xform[0], default_xform[1], default_xform[2]] + ctrl_fcurves = { i.array_index: i for i in fcurves } for keyframe in keyframes: exported = hsPoint3Key() @@ -93,15 +93,16 @@ class AnimationConverter: out_tan = hsVector3() value = hsVector3() for i, subctrl in enumerate(subctrls): - fkey = keyframe.values.get(i, None) - if fkey is not None: - v = fkey.co[1] - last_xform[i] = v - setattr(value, subctrl, v) + fval = keyframe.values.get(i, None) + if fval is not None: + setattr(value, subctrl, fval) setattr(in_tan, subctrl, keyframe.in_tans[i]) setattr(out_tan, subctrl, keyframe.out_tans[i]) else: - setattr(value, subctrl, last_xform[i]) + try: + setattr(value, subctrl, ctrl_fcurves[i].evaluate(keyframe.frame_num_blender)) + except KeyError: + setattr(value, subctrl, default_xform[i]) setattr(in_tan, subctrl, 0.0) setattr(out_tan, subctrl, 0.0) exported.inTan = in_tan @@ -111,11 +112,11 @@ class AnimationConverter: ctrl.keys = (exported_frames, keyframe_type) return ctrl - def _make_quat_controller(self, keyframes, default_xform): + def _make_quat_controller(self, fcurves, keyframes, default_xform): ctrl = plLeafController() keyframe_type = hsKeyFrame.kQuatKeyFrame exported_frames = [] - last_xform = [default_xform[0], default_xform[1], default_xform[2]] + ctrl_fcurves = { i.array_index: i for i in fcurves } for keyframe in keyframes: exported = hsQuatKey() @@ -124,30 +125,34 @@ class AnimationConverter: exported.type = keyframe_type # NOTE: quat keyframes don't do bezier nonsense - value = mathutils.Euler(last_xform, default_xform.order) + value = mathutils.Euler() for i in range(3): - fkey = keyframe.values.get(i, None) - if fkey is not None: - v = fkey.co[1] - last_xform[i] = v - value[i] = v + fval = keyframe.values.get(i, None) + if fval is not None: + value[i] = fval + else: + try: + value[i] = ctrl_fcurves[i].evaluate(keyframe.frame_num_blender) + except KeyError: + value[i] = default_xform[i] quat = value.to_quaternion() exported.value = utils.quaternion(quat) exported_frames.append(exported) ctrl.keys = (exported_frames, keyframe_type) return ctrl - def _make_scalar_controller(self, keyframes, bez_chans, default_xform): + def _make_scalar_controller(self, fcurves, keyframes, bez_chans, default_xform): ctrl = plCompoundController() subctrls = ("X", "Y", "Z") for i in subctrls: setattr(ctrl, i, plLeafController()) exported_frames = ([], [], []) + ctrl_fcurves = { i.array_index: i for i in fcurves } for keyframe in keyframes: for i, subctrl in enumerate(subctrls): - fkey = keyframe.values.get(i, None) - if fkey is not None: + fval = keyframe.values.get(i, None) + if fval is not None: keyframe_type = hsKeyFrame.kBezScalarKeyFrame if i in bez_chans else hsKeyFrame.kScalarKeyFrame exported = hsScalarKey() exported.frame = keyframe.frame_num @@ -155,7 +160,7 @@ class AnimationConverter: exported.inTan = keyframe.in_tans[i] exported.outTan = keyframe.out_tans[i] exported.type = keyframe_type - exported.value = fkey.co[1] + exported.value = fval exported_frames[i].append(exported) for i, subctrl in enumerate(subctrls): my_keyframes = exported_frames[i] @@ -171,13 +176,13 @@ class AnimationConverter: getattr(ctrl, subctrl).keys = (my_keyframes, my_keyframes[0].type) return ctrl - def _make_scale_value_controller(self, keyframes, bez_chans, default_xform): + def _make_scale_value_controller(self, fcurves, keyframes, bez_chans, default_xform): subctrls = ("X", "Y", "Z") keyframe_type = hsKeyFrame.kBezScaleKeyFrame if bez_chans else hsKeyFrame.kScaleKeyFrame exported_frames = [] + ctrl_fcurves = { i.array_index: i for i in fcurves } - _scale = default_xform.to_scale() - last_xform = [_scale[0], _scale[1], _scale[2]] + default_scale = default_xform.to_scale() unit_quat = default_xform.to_quaternion() unit_quat.normalize() unit_quat = utils.quaternion(unit_quat) @@ -192,15 +197,16 @@ class AnimationConverter: out_tan = hsVector3() value = hsVector3() for i, subctrl in enumerate(subctrls): - fkey = keyframe.values.get(i, None) - if fkey is not None: - v = fkey.co[1] - last_xform[i] = v - setattr(value, subctrl, v) + fval = keyframe.values.get(i, None) + if fval is not None: + setattr(value, subctrl, fval) setattr(in_tan, subctrl, keyframe.in_tans[i]) setattr(out_tan, subctrl, keyframe.out_tans[i]) else: - setattr(value, subctrl, last_xform[i]) + try: + setattr(value, subctrl, ctrl_fcurves[i].evaluate(keyframe.frame_num_blender)) + except KeyError: + setattr(value, subctrl, default_scale[i]) setattr(in_tan, subctrl, 0.0) setattr(out_tan, subctrl, 0.0) exported.inTan = in_tan @@ -224,28 +230,27 @@ class AnimationConverter: fcurve.update() for fkey in fcurve.keyframe_points: frame_num, value = fkey.co - if fps == 30.0: - # hope you don't have a frame 29.9 and frame 30.0... - frame_num = int(frame_num) - else: - frame_num = int(frame_num * (30.0 / fps)) keyframe = keyframes.get(frame_num, None) if keyframe is None: keyframe = keyframe_data() - keyframe.frame_num = frame_num + if fps == 30.0: + # hope you don't have a frame 29.9 and frame 30.0... + keyframe.frame_num = int(frame_num) + else: + keyframe.frame_num = int(frame_num * (30.0 / fps)) + keyframe.frame_num_blender = frame_num keyframe.frame_time = frame_num / fps keyframe.in_tans = {} keyframe.out_tans = {} keyframe.values = {} keyframes[frame_num] = keyframe idx = fcurve.array_index - keyframe.values[idx] = fkey + keyframe.values[idx] = value # Calculate the bezier interpolation nonsense if fkey.interpolation == "BEZIER": - og_frame = fkey.co[0] - keyframe.in_tans[idx] = -(value - fkey.handle_left[1]) / (og_frame - fkey.handle_left[0]) / fps / (2 * pi) - keyframe.out_tans[idx] = (value - fkey.handle_right[1]) / (og_frame - fkey.handle_right[0]) / fps / (2 * pi) + keyframe.in_tans[idx] = -(value - fkey.handle_left[1]) / (frame_num - fkey.handle_left[0]) / fps / (2 * pi) + keyframe.out_tans[idx] = (value - fkey.handle_right[1]) / (frame_num - fkey.handle_right[0]) / fps / (2 * pi) bez_chans.add(idx) else: keyframe.in_tans[idx] = 0.0