@@ -131,82 +131,109 @@ def material(obj):
131
131
except IndexError :
132
132
pass
133
133
134
- QUAT_CONVERSION = axis_conversion (from_forward = 'Y' , from_up = 'Z' , to_forward = 'Z' , to_up = 'Y' )
135
-
136
- def __swap_quaternions (track ):
137
- for t in track :
138
- a = t ["value" ]
139
- q = mathutils .Quaternion (a )
140
- q = (QUAT_CONVERSION * q .to_matrix ()).to_quaternion ()
141
- a [0 ] = - q .x
142
- a [1 ] = - q .y
143
- a [2 ] = - q .z
144
- a [3 ] = - q .w
145
- pass
146
-
147
- def __swap_vector3 (track ):
148
- for t in track :
149
- v = t ["value" ]
150
- tmp = v [1 ]
151
- v [1 ] = v [2 ]
152
- v [2 ] = tmp
153
- pass
154
-
155
- def __parse_tracked_vector (fcurves , start_index , nb_curves ):
156
- track = []
134
+ def extract_time (fcurves , start_index ):
135
+ time = []
157
136
for xx in fcurves [start_index ].keyframe_points :
158
- track .append ({ "time" : xx .co .x , "value" : [xx .co .y ] })
137
+ time .append (xx .co .x )
138
+ return time
139
+
140
+ def merge_sorted_lists (l1 , l2 ):
141
+ sorted_list = []
142
+ l1 = l1 [:]
143
+ l2 = l2 [:]
144
+ while (l1 and l2 ):
145
+ h1 = l1 [0 ]
146
+ h2 = l2 [0 ]
147
+ if h1 == h2 :
148
+ sorted_list .append (h1 )
149
+ l1 .pop (0 )
150
+ l2 .pop (0 )
151
+ elif h1 < h2 :
152
+ l1 .pop (0 )
153
+ sorted_list .append (h1 )
154
+ else :
155
+ l2 .pop (0 )
156
+ sorted_list .append (h2 )
157
+ # Add the remaining of the lists
158
+ sorted_list .extend (l1 if l1 else l2 )
159
+ return sorted_list
159
160
160
- swapFunction = __swap_vector3 if nb_curves == 3 else __swap_quaternions
161
+ def appendVec3 (track , time , vec3 ):
162
+ track .append ({ "time" : time , "value" : [ vec3 .x , vec3 .y , vec3 .z ] })
161
163
162
- nb_curves += start_index
163
- start_index += 1
164
- while start_index < nb_curves :
165
- i = 0
166
- for xx in fcurves [start_index ].keyframe_points :
167
- track [i ]["value" ].append (xx .co .y )
168
- i += 1
169
- start_index += 1
170
- swapFunction (track )
171
- return track
164
+ def appendQuat (track , time , quat ):
165
+ track .append ({ "time" : time , "value" : [ quat .x , quat .y , quat .z , quat .w ] })
172
166
173
- # trackable transform fields ( <output field>, <nb fcurve>, <type> )
167
+ # trackable transform fields ( <output field>, <nb fcurve> )
174
168
TRACKABLE_FIELDS = {
175
169
"location" : ( ".position" , 3 , "vector3" ),
176
170
"scale" : ( ".scale" , 3 , "vector3" ),
177
171
"rotation_euler" : ( ".rotation" , 3 , "vector3" ),
178
172
"rotation_quaternion" : ( ".quaternion" , 4 , "quaternion" )
179
173
}
174
+ EXPORTED_TRACKABLE_FIELDS = [ "location" , "scale" , "rotation_quaternion" ]
180
175
181
176
@_object
182
- def animated_xform (obj ):
177
+ def animated_xform (obj , options ):
183
178
fcurves = obj .animation_data
184
179
if not fcurves :
185
- return {}
180
+ return []
186
181
fcurves = fcurves .action .fcurves
187
182
188
183
tracks = []
189
184
i = 0
190
185
nb_curves = len (fcurves )
186
+
187
+ # extract unique frames
188
+ times = None
191
189
while i < nb_curves :
192
190
field_info = TRACKABLE_FIELDS .get (fcurves [i ].data_path )
193
191
if field_info :
194
- nb_curves_local = field_info [1 ]
195
- tracks .append ({
196
- constants .NAME : field_info [0 ],
197
- constants .TYPE : field_info [2 ],
198
- constants .KEYS : __parse_tracked_vector (fcurves , i , nb_curves_local )
199
- })
200
- i += nb_curves_local
192
+ newTimes = extract_time (fcurves , i )
193
+ times = merge_sorted_lists (times , newTimes ) if times else newTimes # merge list
194
+ i += field_info [1 ]
201
195
else :
202
196
i += 1
203
197
204
- animation = [{
198
+ # init tracks
199
+ track_loc = []
200
+ for fld in EXPORTED_TRACKABLE_FIELDS :
201
+ field_info = TRACKABLE_FIELDS [fld ]
202
+ track = []
203
+ track_loc .append (track )
204
+ tracks .append ({
205
+ constants .NAME : field_info [0 ],
206
+ constants .TYPE : field_info [2 ],
207
+ constants .KEYS : track
208
+ })
209
+
210
+ # track arrays
211
+ track_sca = track_loc [1 ]
212
+ track_qua = track_loc [2 ]
213
+ track_loc = track_loc [0 ]
214
+ use_inverted = options .get (constants .HIERARCHY , False ) and obj .parent
215
+
216
+ # for each frame
217
+ inverted_fallback = mathutils .Matrix () if use_inverted else None
218
+ convert_matrix = AXIS_CONVERSION # matrix to convert the exported matrix
219
+ original_frame = context .scene .frame_current
220
+ for time in times :
221
+ context .scene .frame_set (time , 0.0 )
222
+ if use_inverted : # need to use the inverted, parent matrix might have chance
223
+ convert_matrix = obj .parent .matrix_world .inverted (inverted_fallback )
224
+ wm = convert_matrix * obj .matrix_world
225
+ appendVec3 (track_loc , time , wm .to_translation ())
226
+ appendVec3 (track_sca , time , wm .to_scale () )
227
+ appendQuat (track_qua , time , wm .to_quaternion () )
228
+ context .scene .frame_set (original_frame , 0.0 ) # restore to original frame
229
+
230
+ # TODO: remove duplicated key frames
231
+
232
+ return [{
205
233
constants .KEYFRAMES : tracks ,
206
234
constants .FPS : context .scene .render .fps ,
207
235
constants .NAME : obj .name
208
236
}]
209
- return animation
210
237
211
238
@_object
212
239
def mesh (obj , options ):
0 commit comments