Browse Source

Add fcurve/keyframe smashing, mashing, etc.

Don't even ask...
pull/40/head
Adam Johnson 8 years ago
parent
commit
6755453d3c
  1. 111
      korman/exporter/animation.py

111
korman/exporter/animation.py

@ -455,6 +455,115 @@ class AnimationConverter:
final_keyframes = [keyframes[i] for i in sorted(keyframes)]
return (final_keyframes, bezier)
def _process_fcurves(self, fcurves, convert, defaults=None):
"""Processes FCurves of different data sets and converts them into a single list of keyframes.
This should be used when multiple Blender fields map to a single Plasma option."""
class KeyFrameData:
def __init__(self):
self.values = {}
fps = self._bl_fps
pi = math.pi
# It is assumed therefore that any multichannel FCurves will have all channels represented.
# This seems fairly safe with my experiments with Lamp colors...
grouped_fcurves = {}
for fcurve in fcurves:
if fcurve is None:
continue
fcurve.update()
if fcurve.data_path in grouped_fcurves:
grouped_fcurves[fcurve.data_path][fcurve.array_index] = fcurve
else:
grouped_fcurves[fcurve.data_path] = { fcurve.array_index: fcurve }
# Default values for channels that are not animated
for key, value in defaults.items():
if key not in grouped_fcurves:
if hasattr(value, "__len__"):
grouped_fcurves[key] = value
else:
grouped_fcurves[key] = [value,]
# Assemble a dict { PlasmaFrameNum: { FCurveDataPath: KeyFrame } }
keyframe_points = {}
for fcurve in fcurves:
if fcurve is None:
continue
for keyframe in fcurve.keyframe_points:
frame_num_blender, value = keyframe.co
frame_num = int(frame_num_blender * (30.0 / fps))
# This is a temporary keyframe, so we're not going to worry about converting everything
# Only the frame number to Plasma so we can go ahead and merge any rounded dupes
entry, data = keyframe_points.get(frame_num), None
if entry is None:
entry = {}
keyframe_points[frame_num] = entry
else:
data = entry.get(fcurve.data_path)
if data is None:
data = KeyFrameData()
data.frame_num = frame_num
data.frame_num_blender = frame_num_blender
entry[fcurve.data_path] = data
data.values[fcurve.array_index] = value
# Now, we loop through our assembled keyframes and interpolate any missing data using the FCurves
fcurve_chans = { key: len(value) for key, value in grouped_fcurves.items() }
expected_values = sum(fcurve_chans.values())
all_chans = frozenset(grouped_fcurves.keys())
# We will also do the final convert here as well...
final_keyframes = []
for frame_num in sorted(keyframe_points.copy().keys()):
keyframes = keyframe_points[frame_num]
frame_num_blender = next(iter(keyframes.values())).frame_num_blender
# If any data_paths are missing, init a dummy
missing_channels = all_chans - frozenset(keyframes.keys())
for chan in missing_channels:
dummy = KeyFrameData()
dummy.frame_num = frame_num
dummy.frame_num_blender = frame_num_blender
keyframes[chan] = dummy
# Ensure all values are filled out.
num_values = sum(map(len, (i.values for i in keyframes.values())))
if num_values != expected_values:
for chan, sorted_fcurves in grouped_fcurves.items():
chan_keyframes = keyframes[chan]
chan_values = fcurve_chans[chan]
if len(chan_keyframes.values) == chan_values:
continue
for i in range(chan_values):
if i not in chan_keyframes.values:
fcurve = grouped_fcurves[chan][i]
if isinstance(fcurve, bpy.types.FCurve):
chan_keyframes.values[i] = fcurve.evaluate(chan_keyframes.frame_num_blender)
else:
# it's actually a default value!
chan_keyframes.values[i] = fcurve
# All values are calculated! Now we convert the disparate key data into a single keyframe.
kwargs = { data_path: keyframe.values for data_path, keyframe in keyframes.items() }
final_keyframe = KeyFrameData()
final_keyframe.frame_num = frame_num
final_keyframe.frame_num_blender = frame_num_blender
final_keyframe.frame_time = frame_num / fps
value = convert(**kwargs)
if hasattr(value, "__len__"):
final_keyframe.in_tans = [0.0] * len(value)
final_keyframe.out_tans = [0.0] * len(value)
final_keyframe.values = value
else:
final_keyframe.in_tan = 0.0
final_keyframe.out_tan = 0.0
final_keyframe.value = value
final_keyframes.append(final_keyframe)
return final_keyframes
def _process_keyframes(self, fcurves, convert=None):
"""Groups all FCurves for the same frame together"""
keyframe_data = type("KeyFrameData", (), {})
@ -482,7 +591,7 @@ class AnimationConverter:
keyframe.values = {}
keyframes[frame_num] = keyframe
idx = fcurve.array_index
keyframe.values[idx] = value if convert is None else convert(value)
keyframe.values[idx] = value if convert is None else convert(value)
# Calculate the bezier interpolation nonsense
if fkey.interpolation == "BEZIER":

Loading…
Cancel
Save