moves.py 8.9 KB
# -*- coding: UTF-8 -*-

import bpy
import math
import util

def contato(action, input_hand, bones, pose, initialFrame = 18):
    currentFrame = initialFrame
    contact_type = input_hand[1]

    if (contact_type == "alisar"):
        currentFrame = alisar(action, input_hand, pose, bones, initialFrame)
    elif (contact_type == "cocar"):
        currentFrame = cocar(action, input_hand, bones, initialFrame)
    elif (contact_type == "tocar"):
        currentFrame = tocar(action, input_hand, bones, initialFrame)
    elif (contact_type == "riscar"):
        currentFrame = riscar(action, input_hand, bones, initialFrame)
    return currentFrame

def riscar(action, input_hand, bones, pose, initialFrame = 18, bnAntBracoDegree = 2, bnMaoDegree = 45, frameJump = 10):
    currentFrame = initialFrame
    endFrame = initialFrame + 2 * frameJump
    handParam = input_hand[-3:]
    lado = "R" if util.rightBonesConf == bones else "L"

    bnAntBraco = bpy.context.object.pose.bones["BnAntBraco." + lado]
    bnAntBraco.bone.select = True
    util.apply_rotation(bnAntBraco, "Z", currentFrame, endFrame, bnAntBracoDegree)
    currentFrame += frameJump
    util.apply_rotation(bnAntBraco, "Z", currentFrame, endFrame, (-1)*(bnAntBracoDegree+1))
    bnAntBraco.bone.select = False

    currentFrame = initialFrame
    util.setPose(action, handParam, [currentFrame], bones)
    bnMao = bpy.context.object.pose.bones["BnMao." + lado]
    bnMao.bone.select = True
    util.apply_rotation(bnMao, "Y", currentFrame, endFrame, bnMaoDegree)
    currentFrame += frameJump
    util.apply_rotation(bnMao, "Y", currentFrame, endFrame, (-2)*bnMaoDegree)
    currentFrame += frameJump
    util.apply_rotation(bnMao, "Y", currentFrame, endFrame, bnMaoDegree)
    util.setPose([action[0]], [handParam[0]], [currentFrame], bones)
    currentFrame += frameJump
    bnMao.bone.select = False
    return currentFrame

def tocar(action, input_hand, bones, pose, initialFrame = 18, degree = 30, frameJump = 10):
    currentFrame = initialFrame
    endFrame = initialFrame + 2 * frameJump
    handParam = input_hand[-3:]
    util.setPose(action, handParam, [initialFrame], bones)

    lado = "BnMao.R" if util.rightBonesConf == bones else "BnMao.L"
    bnMao =  bpy.context.object.pose.bones[lado]
    bnMao.bone.select = True
    currentFrame += frameJump
    util.apply_rotation(bnMao, "X", currentFrame, endFrame, -degree)
    currentFrame += frameJump
    util.apply_rotation(bnMao, "X", currentFrame, endFrame, degree)
    util.setPose([action[0]], [handParam[0]], [currentFrame], bones)
    currentFrame += frameJump
    bnMao.bone.select = False
    return currentFrame

def cocar(action, input_hand, bones, initialFrame = 18, repetition = 2, frameJump = 6):
    currentFrame = initialFrame
    pa_index = input_hand[-1]

    for i in range(0, repetition):
        util.setPose(action, [util.cocar_mao_aberta_index, pa_index, util.cocar_orientation_index], [currentFrame], bones)
        currentFrame += frameJump
        lastFrame = i == repetition - 1
        util.setPose(action, [util.cocar_mao_fechada_index, pa_index, util.cocar_orientation_index], [currentFrame], bones)
        currentFrame += frameJump
    return currentFrame

def alisar(action, input_hand, pose, bones, initialFrame = 18, frameJump = 10, width = 0.25):
    currentFrame = initialFrame
    orientation, repetition = input_hand[2:4]
    handParam = input_hand[-3:]
    util.setPose(action, handParam, util.hands_default_frames, bones)

    if (orientation == "perpendicular"):
        currentFrame = alisar_xy(pose, 1, repetition, initialFrame, frameJump, width)
    elif (orientation == "paralelo"):
        currentFrame = alisar_xy(pose, 0, repetition, initialFrame, frameJump, width)
    elif (orientation == "diagonal-direita"):
        currentFrame = alisar_diagonal(pose, True, repetition, initialFrame, frameJump, width)
    elif (orientation == "diagonal-esquerda"):
        currentFrame = alisar_diagonal(pose, False, repetition, initialFrame, frameJump, width)

    util.setPose(action, handParam, [currentFrame], bones)
    return currentFrame

def alisar_xy(pose, orientation_index, repetition, initialFrame = 18, frameJump = 10, width = 0.25):
    currentFrame = initialFrame
    center =  pose.location.x, pose.location.y, pose.location.z

    for i in range(0, repetition):
        pose.location[orientation_index] = center[orientation_index] - width
        util.keyframe_insert(pose, 'location', currentFrame)
        currentFrame += frameJump
        pose.location[orientation_index] = center[orientation_index] + width
        util.keyframe_insert(pose, 'location', currentFrame)
        currentFrame += frameJump
    return currentFrame

def alisar_diagonal(pose, to_right, repetition, initialFrame = 18, frameJump = 10, width = 0.25):
    currentFrame = initialFrame
    center =  pose.location.x, pose.location.y, pose.location.z

    for i in range(0, repetition):
        pose.location[0] = center[0] - width if to_right else center[0] - width
        pose.location[1] = center[1] - width if to_right else center[1] + width

        util.keyframe_insert(pose, 'location', currentFrame)
        currentFrame += frameJump

        pose.location[0] = center[0] + width if to_right else center[0] + width
        pose.location[1] = center[1] + width if to_right else center[1] - width
        util.keyframe_insert(pose, 'location', currentFrame)
        currentFrame += frameJump
    return currentFrame

"""
# descontinuada: circular_or_semiCircular
def circular_or_semiCircular(pose, orientation, direction, radius, laps, intensity = 5, initialFrame = 18, turn = None):
    center =  pose.location.x, pose.location.y, pose.location.z
    if(orientation == 'perpendicular'):
        if(direction == 'horario'):
            endFrame = circular(center, radius, 1, 0, 2, pose, 0, laps, intensity, initialFrame, turn)
        else:
            endFrame = locationCircular(center, radius, 0, 1, 2, pose, 0, laps, intensity, initialFrame, turn)
    elif(orientation == 'paralelo'):
        if(direction == 'horario'):
            endFrame = locationCircular(center, radius, 1, 2, 0, pose, 0, laps, intensity, initialFrame, turn)
        else:
            endFrame = locationCircular(center, radius, 2, 1, 0, pose, 0, laps, intensity, initialFrame, turn)
    elif(orientation == 'plano'):
        if(direction == 'horario'):
            endFrame = locationCircular(center, radius, 2, 0, 1, pose, 0, laps, intensity, initialFrame, turn)
        else:
            endFrame = locationCircular(center, radius, 0, 2, 1, pose, 0, laps, intensity, initialFrame, turn)
    return endFrame
"""

# Obs.: A velocidade do movimento vai ser a relacao entre tamanho do raio e o periodo
#       quanto maior o periodo mais keyframes
#       quanto menor o raio mais rapido
# exemplos:
# raio: "pequeno" raio = 0.5, velocidade: "rapido" periodo = 25
# raio: "pequeno" raio = 0.5, velocidade: "normal" periodo = 35
# raio: "pequeno" raio = 0.5, velocidade: "lento" periodo = 45
# raio: "normal" raio = 1.0, velocidade: "rapido" periodo = 35
# raio: "normal" raio = 1.0, velocidade: "normal" periodo = 45
# raio: "normal" raio = 1.0, velocidade: "lento" periodo = 55
# raio: "grande" raio = 1.5, velocidade: "rapido" periodo = 45
# raio: "grande" raio = 1.5, velocidade: "normal" periodo = 55
# raio: "grande" raio = 1.5, velocidade: "lento" periodo = 65
# @param obj: (objeto) bone, mesh, e.g.
# @param itFrame: (int) posicao onde o primeiro keyframe vai ser inserido
# @param raio: (int) raio da circunferencia
# @param periodo: (int) quantidade de keyframes necessarios para completar uma volta completa
# @param x: (int) in [0,1,2] define qual eixo vai variar no seno (0 = eixo X, 1 = eixo Y, 2 = eixo Z)
# @param y: (int) in [0,1,2] define qual eixo vai variar no cosseno (0 = eixo X, 1 = eixo Y, 2 = eixo Z)
# @param ladoOposto: (bool) inverte o lado da primeira posicao (pode ser util em alguns casos para espelhar)
# @param inverterDirecao (bool) inverte o sentido do movimento (horario para anti-horario)
def circular(obj, itFrame, raio, periodo, x = 0, y = 1, ladoOposto = False, inverterDirecao = False):
    # limita inferiormente
    if (periodo < 16):
        periodo = 16
    # limita superiormente
    elif (periodo > 360):
        periodo = 360
    # muda lado inicial
    if (ladoOposto):
        k = round(periodo / 2)
    else:
        k = 0
    # evita estouro dos indices
    x %= 3
    y %= 3
    # inverte direcao do movimento
    if (inverterDirecao):
        tmp = x
        x = y
        y = tmp
    # copia posicao inicial para transladar
    loc = [obj.location[0], obj.location[1], obj.location[2]]
    for i in range(k, periodo + k):
        # pequena otimizacao para reduzir a quantidade de keyframes
        if (itFrame % 2 == 0):
            obj.location[x] = loc[x] + (raio * math.cos(i / periodo * (2 * math.pi)))
            obj.location[y] = loc[y] + (raio * math.sin(i / periodo * (2 * math.pi)))
            obj.keyframe_insert(data_path='location', frame=itFrame, index=-1)
        itFrame += 1
    return periodo - 1