libras.py 8.61 KB
# -*- coding: UTF-8 -*-

# importa modulo do Blender
import bpy

# importa modulos do Python
import json
import sys
import os

# define o caminho absoluto do diretorio deste arquivo
getcwd = os.path.dirname(os.path.abspath(__file__))

# insere o caminho do diretorio atual no path (permite o acesso aos modulos locais)
sys.path.insert(0, getcwd)

# importa modulos locais
import util
import moves
import pyutil
import facial

# intervalos de interpolacao dos keyframes
dict_interpolation = {
    'inicial': 20,
    'lento': 5,
    'normal': 10,
    'rapido': 15,
    'final': 20
}

def insert_keyframe_pose_default(current_frame = 0, frame_jump = 0, pose_bones = bpy.context.object.pose.bones, types_keyframe = ['location', 'rotation_quaternion']):
    for obj in (pose_bones):
        obj.bone.select = True
        for type_keyframe in types_keyframe:
            obj.keyframe_insert(index = -1, frame = current_frame, group = obj.name, data_path = type_keyframe)
        obj.bone.select = False
    return current_frame + frame_jump

def pose_default(current_frame = 0, frame_jump = 0, actions = bpy.data.actions):
    result = 0
    for action in actions:
        if (action.use_fake_user):
            bpy.context.object.pose_library = action
            bpy.ops.poselib.apply_pose(pose_index = 0)
            result = insert_keyframe_pose_default(current_frame, frame_jump)
    return result

def decode_circular_semicircular(js_movement, current_frame, frame_jump, is_right_hand, is_semicircular):
    # const
    dict_ray = {'pequeno': 0.5, 'normal': 1.0, 'grande': 1.5}
    dict_period = {'lento': 55, 'normal': 45, 'rapido': 35}
    # decodificar valores
    ray = dict_ray[js_movement['raio']]
    period = dict_period[js_movement['velocidade']]
    print('setar articulacao:', js_movement['articulacao'])
    print('setar configuracao:', js_movement['configuracao'])
    print('setar orientacao:', js_movement['orientacao'])
    # diminuir a velocidade
    if (js_movement['velocidade'] == 'lento'):
        period += 10
    # aumentar a velocidade
    elif (js_movement['velocidade'] == 'rapido'):
        period -= 10
    # definir eixos do movimento
    if (js_movement['plano'] == 'frente-esquerda'):
        x, y = 2, 0
    elif (js_movement['plano'] == 'frente-cima'):
        x, y = 2, 1
    else:
        x, y = 0, 1
    # mao usada (direita/esquerda)
    if (is_right_hand):
        ik = bpy.context.object.pose.bones['ik_FK.R']
    else:
        ik = bpy.context.object.pose.bones['ik_FK.L']
    current_frame = insert_keyframe_pose_default(current_frame, frame_jump, [ik], ['location'])
    current_frame = moves.circular(ik, current_frame + frame_jump, ray, period, x, y, js_movement['lado_oposto'], js_movement['sentido_inverso'], is_semicircular)
    return current_frame

def decode_hand_mov(current_frame, frame_jump, js_mao, is_right_hand):
    if (js_mao == {}):
        return
    movement_name = next(iter(js_mao.keys()))
    print("Movimento: " + movement_name)
    if (movement_name == 'circular'):
        current_frame = decode_circular_semicircular(js_mao[movement_name], current_frame, frame_jump, is_right_hand, False)
    elif (movement_name == 'semicircular'):
        current_frame = decode_circular_semicircular(js_mao[movement_name], current_frame, frame_jump, is_right_hand, True)
    return current_frame + frame_jump

"""
# Funcao responsavel por setar pose padrao
def poseDefault(json_input, positionFrames, collisionFlag = False):
    handDefaultParam = [0, 0, 0]
    util.setPose(util.right_hand_actions, handDefaultParam, positionFrames, util.rightBonesConf, collisionFlag)
    if(json_input["leftHand"] != []):
        util.setPose(util.left_hand_actions, handDefaultParam, positionFrames, util.leftBonesConf, collisionFlag)
    setFaceConfiguration([0], positionFrames, util.faceBonesConf)

# Funcao responsavel por setar as configuracoes das maos
def setHandConfiguration(actions, handParam, positionFrames, bones):
    util.setPose(actions, handParam, positionFrames, bones)

# Funcao responsavel por setar a configuracao da face
def setFaceConfiguration(handParam, positionFrames, bones):
    util.setPose(util.facial_expression_action, handParam, positionFrames, bones)

#Funcao que inicia a configuracao de ambas as maos
def configureHands(endFrame):
    # Array com valores dos campos que serao passados pelo JSON
    hands = ["rightHand", "leftHand"]
    iks = ["ik_FK.R", "ik_FK.L"]
    bones_ = [util.rightBonesConf, util.leftBonesConf]
    # Array com as actions FAKES que seram selecionadas no Blender para cada lado do corpo
    actions = [util.right_hand_actions, util.left_hand_actions]
    for i in range(len(hands)):
        if(json_input[hands[i]] != []):
            move = json_input[hands[i]][0]
            pose = util.armature.pose.bones[iks[i]]
            handParam = json_input[hands[i]][-3:]
            if(move in ["pontual", "circular", "semicircular", "retilineo", "senoidal"]):
                setHandConfiguration(actions[i], handParam, util.hands_default_frames, bones_[i])
            if(move in ["circular", "semicircular"]):
                orientation, direction, radius, laps = json_input[hands[i]][1:5]
                #endFrame = moves.circular_or_semiCircular(pose, orientation, direction, radius, laps, 5)
                setHandConfiguration(actions[i], handParam, [endFrame], bones_[i])
            elif(move == "retilineo"):
                setHandConfiguration(actions[i], json_input[hands[i]][-6:-3], util.hands_default_frames, bones_[i])
                setHandConfiguration(actions[i], handParam, util.hands_frames_retilineo, bones_[i])
            elif(move == "senoidal"):
                orientation, direction, radius, laps = json_input[hands[i]][1:5]
                #endFrame = circular_or_semiCircular(pose, orientation, direction, radius, laps, 5)
                setHandConfiguration(actions[i], handParam, [endFrame], bones_[i])
            elif(move == "contato"):
                endFrame = moves.contato(actions[i], json_input[hands[i]], bones_[i], pose)
"""

def main():
    util.delete_all_keyframes()
    util.configure_output()
    bpy.context.scene.animation_data_create()

    try:
        js_input = json.loads(sys.argv[6])
        js_movimentos = js_input['movimentos']
        frame_jump =  dict_interpolation[js_input['interpolacao']]

        endFrame = pose_default(0)
        mao_esquerda_frame = 0
        mao_direita_frame = 0

        # pose padrao inicial em todos os bones ('location' e 'rotation_quaternion')
        endFrame += pose_default(dict_interpolation['inicial'])

        for i in range(0, len(js_movimentos)):
            # tenta decodificar objetos JSON
            try:
                js_facial = js_movimentos[i]['facial']
            except:
                js_facial = {}
            try:
                js_mao_esquerda = js_movimentos[i]['mao_esquerda']
            except:
                js_mao_esquerda = {}
            try:
                js_mao_direita = js_movimentos[i]['mao_direita']
            except:
                js_mao_direita = {}

            # faz tratamento dos objetos
            if (js_facial == {}):
                pyutil.log("<Vazio> js_movimentos[%d] >> Exp facial" % (i))
                facial.set_expression(0, facial.timeline_facial + frame_jump)
            else:
                facial.decode_expression(js_facial)

            if (js_mao_esquerda == {}):
                pyutil.log("<Vazio> js_movimentos[%d] >> Mao esquerda" % (i))
                # TODO posicionar mao esquerda na lateral do corpo
            else:
                mao_esquerda_frame += decode_hand_mov(mao_esquerda_frame, frame_jump, js_mao_esquerda, False)

            if (js_mao_direita == {}):
                pyutil.log("<Vazio> js_movimentos[%d] >> Mao direita" % (i))
                # TODO posicionar mao direita na lateral do corpo
            else:
                mao_direita_frame += decode_hand_mov(mao_direita_frame, frame_jump, js_mao_direita, True)

            endFrame = max(facial.timeline_facial, mao_esquerda_frame, mao_direita_frame)
            endFrame += frame_jump

        # setar pose padrao final em todos os bones (location e rotation)
        #endFrame += pose_default(endFrame + dict_interpolation['final'])
        #endFrame = insert_keyframe_pose_default(endFrame, frame_jump)
        #endFrame += dict_interpolation['final']
        #endFrame = util.get_endFrame(js_input, util.hands_frames_retilineo)
        #poseDefault([1])
        #configureHands(endFrame)
        #configureFace(endFrame)
        #poseDefault(js_input, [endFrame + 15])

        util.render_sign(js_input["userId"], js_input["sinal"], endFrame)

    except:
        pyutil.print_stack_trace(__file__)
        raise

if __name__ == "__main__":
    main()