Beispiel #1
0
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 shorten_quaternion_paths(qs):
    """
    Given a list of quaternions, return a list of quaternions which produce the
    same rotations but where each element is always the closest quaternion to
    its predecessor.

    Applying this to the ordinates of a curve ensure rotation always takes the
    "shortest path". See glTF issue #1395.
    """
    # Also note: it does not matter if you apply this before or after coordinate
    # conversion :)
    res = []
    if qs: res.append(qs[0])
    for i in range(1, len(qs)):
        q = Quaternion(qs[i])
        res.append(-q if q.dot(res[-1]) < 0 else q)
    return res
Beispiel #3
0
def sequence_items_from_action(action, sequence_items, action_data, action_type, frame_count, animation_type):
    if animation_type == "REGULAR":
        locations_map = {}
        rotations_map = {}
        scales_map = {}
        bones_map = action_data

        p_bone: PoseBone
        for parent_tag, p_bone in bones_map.items():
            pos_vector_path = p_bone.path_from_id("location")
            rot_quaternion_path = p_bone.path_from_id("rotation_quaternion")
            rot_euler_path = p_bone.path_from_id("rotation_euler")
            scale_vector_path = p_bone.path_from_id("scale")

            # Get list of per-frame data for every path

            b_locations = evaluate_vector(
                action.fcurves, pos_vector_path, frame_count)
            b_quaternions = evaluate_quaternion(
                action.fcurves, rot_quaternion_path, frame_count)
            b_euler_quaternions = evaluate_euler_to_quaternion(
                action.fcurves, rot_euler_path, frame_count)
            b_scales = evaluate_vector(
                action.fcurves, scale_vector_path, frame_count)

            # Link them with Bone ID

            if len(b_locations) > 0:
                locations_map[parent_tag] = b_locations

            # Its a bit of a edge case scenario because blender uses either
            # euler or quaternion (I cant really understand why quaternion doesnt update with euler)
            # So we will prefer quaternion over euler for now
            # TODO: Theres also third rotation in blender, angles or something...
            if len(b_quaternions) > 0:
                rotations_map[parent_tag] = b_quaternions
            elif len(b_euler_quaternions) > 0:
                rotations_map[parent_tag] = b_euler_quaternions

            if len(b_scales) > 0:
                scales_map[parent_tag] = b_scales

        # Transform position from local to armature space
        for parent_tag, positions in locations_map.items():
            p_bone = bones_map[parent_tag]
            bone = p_bone.bone

            for frame_id, position in enumerate(positions):
                mat = bone.matrix_local

                if bone.parent is not None:
                    mat = bone.parent.matrix_local.inverted() @ bone.matrix_local

                    mat_decomposed = mat.decompose()

                    bone_location = mat_decomposed[0]
                    bone_rotation = mat_decomposed[1]

                    position.rotate(bone_rotation)

                    diff_location = Vector((
                        (position.x + bone_location.x),
                        (position.y + bone_location.y),
                        (position.z + bone_location.z),
                    ))

                    positions[frame_id] = diff_location

        # Transform rotation from local to armature space
        for parent_tag, quaternions in rotations_map.items():
            p_bone = bones_map[parent_tag]
            bone = p_bone.bone

            prev_quaternion = None
            for quaternion in quaternions:
                if p_bone.parent is not None:
                    pose_rot = Matrix.to_quaternion(bone.matrix)
                    quaternion.rotate(pose_rot)

                if prev_quaternion is not None:
                    # "Flickering bug" fix - killso:
                    # This bug is caused by interpolation algorithm used in GTA
                    # which is not slerp, but straight interpolation of every value
                    # and this leads to incorrect results in cases if dot(this, next) < 0
                    # This is correct "Quaternion Lerp" algorithm:
                    # if (Dot(start, end) >= 0f)
                    # {
                    #   result.X = (1 - amount) * start.X + amount * end.X
                    #   ...
                    # }
                    # else
                    # {
                    #   result.X = (1 - amount) * start.X - amount * end.X
                    #   ...
                    # }
                    # (Statement difference is only substracting instead of adding)
                    # But GTA algorithm doesn't have Dot check,
                    # resulting all values that are not passing this statement to "lag" in game.
                    # (because of incorrect interpolation direction)
                    # So what we do is make all values to pass Dot(start, end) >= 0f statement
                    if Quaternion.dot(prev_quaternion, quaternion) < 0:
                        quaternion *= -1

                prev_quaternion = quaternion
        # WARNING: ANY OPERATION WITH ROTATION WILL CAUSE SIGN CHANGE. PROCEED ANYTHING BEFORE FIX.

        if len(locations_map) > 0:
            sequence_items[ensure_action_track(
                TrackType.BonePosition, action_type)] = locations_map

        if len(rotations_map) > 0:
            sequence_items[ensure_action_track(
                TrackType.BoneRotation, action_type)] = rotations_map

        if len(scales_map) > 0:
            sequence_items[ensure_action_track(
                TrackType.BoneScale, action_type)] = scales_map

    elif animation_type == "UV":
        u_locations_map = {}
        v_locations_map = {}
        uv_mat = action
        uv_nodetree = uv_mat.node_tree
        mat_nodes = uv_nodetree.nodes
        vector_math_node = None

        # Verify if material has required node(Vector Math) to get animation data
        for node in mat_nodes:
            if node.type == 'VECT_MATH':
                vector_math_node = node
                break
        if vector_math_node is None:
            raise Exception("Unable to find Vector Math node in material to get UV animation data!")
        else:
            pos_vector_path = vector_math_node.inputs[1].path_from_id("default_value")
            uv_fcurve = uv_nodetree.animation_data.action.fcurves
            uv_locations = evaluate_vector(
                    uv_fcurve, pos_vector_path, frame_count)
            if len(uv_locations) > 0:
                u_channel_loc = []
                v_channel_loc = []
                for vector in uv_locations:
                    u_channel_loc.append(round(vector.x, 4))
                    v_channel_loc.append(-round(vector.y, 4))

                if len(u_channel_loc) > 0:
                        u_locations_map[0] = u_channel_loc
                        
                if len(v_channel_loc) > 0:
                        v_locations_map[0] = v_channel_loc

            if len(u_locations_map) > 0:
                sequence_items[ensure_action_track(
                    TrackType.UV0, action_type)] = u_locations_map

            if len(v_locations_map) > 0:
                sequence_items[ensure_action_track(
                    TrackType.UV1, action_type)] = v_locations_map
Beispiel #4
0
    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'}