def rigRecon(input, context, timeOffset, rot, transl): for name in input.keys(): entry = input[name] bpy.ops.object.select_pattern(pattern=name + "*", extend=False) print("pattern: %s" % name + '*') obj = context.selected_objects[0] print("Keyframing %s" % obj.name) prevPose = None prevEuler = None offset = Vector((0, 0, 0)) for sFrameId in entry['log'].keys(): state = entry['log'][sFrameId] frameId = int(sFrameId) #print( "Adding keyFrame %d" % frameId ) context.scene.frame_set(frameId) obj.location = state['pos'] obj.rotation_mode = 'QUATERNION' q = Quaternion(state['pose']) if prevPose: if q.dot(prevPose) < 0: q.negate() #print('newq:',q) # else: # print('dotok:', prevPose, q, q.dot(prevPose)) obj.rotation_quaternion = q #obj.rotation_euler = q.to_euler('XYZ') #obj.rotation_euler.x += offset.x #obj.rotation_euler.y += offset.y #obj.rotation_euler.z += offset.z #if prevEuler: # d = Vector(obj.rotation_euler) - Vector(prevEuler) # if d.length > 1: # print("[",sFrameId,"] d: ", d ) # print('prev: ', prevEuler, 'new: ', obj.rotation_euler) # if abs(d.x) > math.pi/2: # offset.x += 2*math.pi # obj.rotation_euler.x += 2*math.pi # print( "offset.x:" , offset.x, 'newx: ', obj.rotation_euler.x ) # if abs(d.y) > math.pi/2: # offset.y += 2*math.pi # obj.rotation_euler.y += 2*math.pi # print( "offset.y:" , offset.y, 'newy: ', obj.rotation_euler.y ) # if abs(d.z) > math.pi/2: # offset.z += 2*math.pi # obj.rotation_euler.z += 2*math.pi # print( "offset.z:" , offset.z, 'newz: ', obj.rotation_euler.z ) #obj.rotation_euler.x -= math.pi / 2. #bpy.ops.anim.keyframe_insert() #obj.keyframe_insert( data_path="LocRot", index=-1,frame=frameId) bpy.ops.anim.keying_set_active_set(type='BUILTIN_KSI_LocRot') bpy.ops.anim.keyframe_insert() #obj.keyframe_insert(index=-1) #obj.keyframe_insert(data_path="location", index=-1, frame=frameId) #obj.keyframe_insert(data_path="rotation", index=-1, frame=frameId) prevPose = q.copy() prevEuler = obj.rotation_euler.copy()
def remove_quaternion_discontinuities(target_obj): # the interpolation of quaternions may lead to discontinuities # if the quaternions show different signs # https://blender.stackexchange.com/questions/58866/keyframe-interpolation-instability action = target_obj.animation_data.action # quaternion curves fqw = action.fcurves.find("rotation_quaternion", index=0) fqx = action.fcurves.find("rotation_quaternion", index=1) fqy = action.fcurves.find("rotation_quaternion", index=2) fqz = action.fcurves.find("rotation_quaternion", index=3) # invert quaternion so that interpolation takes the shortest path if len(fqw.keyframe_points) > 0: current_quat = Quaternion(( fqw.keyframe_points[0].co[1], fqx.keyframe_points[0].co[1], fqy.keyframe_points[0].co[1], fqz.keyframe_points[0].co[1], )) for i in range(len(fqw.keyframe_points) - 1): last_quat = current_quat current_quat = Quaternion(( fqw.keyframe_points[i + 1].co[1], fqx.keyframe_points[i + 1].co[1], fqy.keyframe_points[i + 1].co[1], fqz.keyframe_points[i + 1].co[1], )) if last_quat.dot(current_quat) < 0: current_quat.negate() fqw.keyframe_points[i + 1].co[1] = -fqw.keyframe_points[i + 1].co[1] fqx.keyframe_points[i + 1].co[1] = -fqx.keyframe_points[i + 1].co[1] fqy.keyframe_points[i + 1].co[1] = -fqy.keyframe_points[i + 1].co[1] fqz.keyframe_points[i + 1].co[1] = -fqz.keyframe_points[i + 1].co[1]
def operation_negate(self, q): qn = Quaternion(q) qn.negate() return qn
def operation_negate(self, q): qn = Quaternion(q) qn.negate() return qn
def execute(self, context): data = [] objId = 0 for ob in bpy.data.objects: if (ob.physacq.is_actor): print(ob.name) o = {} o['name'] = ob.name o['objId'] = objId o['shape'] = ob.physacq.shape o['size'] = { "x": ob.dimensions[0], "y": ob.dimensions[1], "z": ob.dimensions[2] } o['mass'] = ob.physacq.mass log = {} if not ob.animation_data: continue action = ob.animation_data.action for fcu in action.fcurves: #print( "fcu: ", fcu ) #print( "prop: ", fcu.data_path ) #print( "propId: ", fcu.array_index ) if fcu.data_path == 'location': logKey = 'pos' elif fcu.data_path == 'rotation_euler': logKey = 'pose' elif fcu.data_path == 'rotation_quaternion': logKey = 'pose' elif fcu.data_path == 'scale': continue else: print("Can't interpret keyframe type, attention!!!", fcu.data_path) continue if fcu.array_index == 0: subKey = 'x' elif fcu.array_index == 1: subKey = 'y' elif fcu.array_index == 2: subKey = 'z' elif fcu.array_index == 3: subKey = 'w' else: print("Unprepared!") keyframe_points = fcu.keyframe_points for entry in keyframe_points: #print( entry.co ) #print( "key:", str(int(entry.co[0])) ) frameId = str(int(entry.co[0])) if frameId not in log: log[frameId] = {} if logKey not in log[frameId]: log[frameId][logKey] = {} log[frameId][logKey][subKey] = entry.co[1] prevKey = None prevQ = None for key, frame in log.items(): if 'pos' in log[key]: pos = Vector( coordinatesUtil.jsonVector3ToTuple( log[key]['pos'])) log[key]['pos'] = coordinatesUtil.vector3ToJson( self.coordChangeM * pos) if 'pose' not in log[key]: continue #print( 'ob.rotation_mode:', ob.rotation_mode) if ob.rotation_mode == 'XYZ': v = Vector( coordinatesUtil.jsonVector3ToTuple( log[key]['pose'])) eul = Euler(v, ob.rotation_mode) q = eul.to_quaternion() elif ob.rotation_mode == 'QUATERNION': entry = log[key]['pose'] print(entry) q = Quaternion(( entry['x'], entry['y'], entry['z'], entry['w'])) # yes, array_index==3 was parsed to w if prevQ: dotProd = q.dot(prevQ) if dotProd < 0: print("dot: ", dotProd) #q.negate() #print( "q: %s" % (q.__repr__()) ) #log[ key ] ['pose'] = { 'x' : q[1], 'y' : -q[3], 'z': q[2], 'w' : q[0] } log[key]['pose'] = coordinatesUtil.quatToJson( coordinatesUtil.quatFromBlender(q)) if prevKey: #print( "check: ", log[prevKey]['pose'], "\n",log[key]['pose'] ) q2 = Quaternion(q) q2.negate() #print( "q:", q, "negative: ", q2 ) prevKey = key prevQ = q o['log'] = log data.append(o) objId += 1 if not len(data): self.report({'WARNING'}, "No keyframes, not saving") return {'FINISHED'} fp = context.scene.physacq.savePath if len(bpy.path.basename(fp)) == 0: fp = "//cuboids.json" if fp.find("//") >= 0: fp = bpy.path.abspath(fp) self.report({'INFO'}, "Saving poses to %s" % (fp)) f = open(fp, 'w') json.dump(data, f) f.close() return {'FINISHED'}
fqz = action.fcurves.find('rotation_quaternion', index = 3) # invert quaternion so that interpolation takes the shortest path if fqw is not None and fqw.keyframe_points is not None and len(fqw.keyframe_points) > 0: endQuat = Quaternion( ( fqw.keyframe_points[0].co[1], fqx.keyframe_points[0].co[1], fqy.keyframe_points[0].co[1], fqz.keyframe_points[0].co[1] ) ) for i in range(len(fqw.keyframe_points)-1): startQuat = endQuat endQuat = Quaternion( ( fqw.keyframe_points[i+1].co[1], fqx.keyframe_points[i+1].co[1], fqy.keyframe_points[i+1].co[1], fqz.keyframe_points[i+1].co[1] ) ) if startQuat.dot(endQuat) < 0: endQuat.negate() fqw.keyframe_points[i+1].co[1] = -fqw.keyframe_points[i+1].co[1] fqx.keyframe_points[i+1].co[1] = -fqx.keyframe_points[i+1].co[1] fqy.keyframe_points[i+1].co[1] = -fqy.keyframe_points[i+1].co[1] fqz.keyframe_points[i+1].co[1] = -fqz.keyframe_points[i+1].co[1]