diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..71dad6e --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +BLENDER = blender +DONE = [\33[30;32mOK\33[m]\n +FAIL = [\33[30;31mERRO\33[m]\n +MODULE = Wikilibras +CLEAR = @echo -n "\033c" +CACHE = __pycache__ +SCRIPT = libras.py +AVATAR = avatar_Hozana_wikiLibras.blend +JSON = '{"userId": 4,"rightHand": ["circular", "perpendicular", "horario", 0.6, 1, 20, 4, 6], "leftHand":["pontual", 10, 3, 3], "facialExp": [6], "signName":"teste_circular"}' + +default: main + +main: + $(CLEAR) + @echo Executando... + @$(BLENDER) -b $(AVATAR) -P $(SCRIPT) $(JSON) && echo "$(DONE)" || { echo "$(FAIL)"; exit 1; } + +clean: + $(CLEAR) + @echo -n "Limpando..." + @rm -rf $(CACHE) > /dev/null 2>&1 && echo " $(DONE)" || { echo " $(FAIL)"; exit 1; } diff --git a/libras.py b/libras.py index 0f42242..5ba79d2 100644 --- a/libras.py +++ b/libras.py @@ -1,29 +1,24 @@ # -*- coding: UTF-8 -*- -# importa modulos do Python -import sys +# importa modulos do Blender e Python +import bpy +import json import os -# insere o diretorio atual no path -# permite que o código seja executado de qualquer diretório, possibilitando acesso aos modulos locais +import sys + +# insere o diretorio atual no path (permite o acesso aos modulos locais) sys.path.append(os.getcwd()) -# importa modulos nativos do Blender e Python -import bpy -import json # importa modulos locais import util import moves -# verifica a quantidade de argumentos recebidos -if (len(sys.argv) != 6): - print ("WikiLibras: Invalid number of arguments") - exit(1) - # tenta decodificar o argumento JSON recebido try: + util.file_rename("./users/4/teste_circular_0001-0083.mp4") json_input = json.loads(sys.argv[5]) -except (ValueError, KeyError, TypeError): - print ("WikiLibras: JSON format error") +except Exception: + util.printStackTrace(__file__) exit(1) # ajusta as configuraçẽs de renderização @@ -38,12 +33,12 @@ hands_frames_retilineo = [30,33] armature = bpy.context.scene.objects.get('Armature.001') # Cria uma Action -act = bpy.context.scene.animation_data_create() +act = bpy.context.scene.animation_data_create() -# Função responsável por selecionar as pose-libs e setar os frames +# Função responsável por selecionar as pose-libs e setar os frames def setPose(actions, parametesConf, positionFrames, bones): bpy.ops.object.mode_set(mode = 'OBJECT') - bpy.ops.object.select_all(action="DESELECT") + bpy.ops.object.select_all(action="DESELECT") bpy.ops.object.mode_set(mode = 'POSE') for l in range(len(actions)): armature.pose_library = bpy.data.actions[actions[l]] @@ -54,8 +49,8 @@ def setPose(actions, parametesConf, positionFrames, bones): armature.pose.bones[bones[i]].keyframe_insert(data_path = 'rotation_quaternion', index = -1, frame = positionFrames[x]) # Função responsável por setar pose padrão -def poseDefault(positionFrames, bones): - setPose([0], [0], positionFrames, bones) +def poseDefault(positionFrames, bones): + setPose([0], [0], positionFrames, bones) # Função responsável por setar as configuraçẽs das mãos def generationConfigurations(actions, handParam, positionFrames, bones): @@ -72,11 +67,11 @@ initialFrame, endFrame = 15, util.get_endFrame(json_input,hands_frames_retilineo #Função que inicia a configuração de ambas as mãos def configureHands(): # Array com valores dos campos que serão passados pelo JSON - hands = ["rightHand", "leftHand"] + 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 = [[1, 3, 5], [2, 4, 6]] + actions = [[1, 3, 5], [2, 4, 6]] global endFrame for i in range(len(hands)): if(json_input[hands[i]] != []): @@ -93,18 +88,22 @@ def configureHands(): elif(json_input[hands[i]][0] == "retilineo"): generationConfigurations(actions[i], json_input[hands[i]][-6:-3], hands_default_frames, bones_[i]) generationConfigurations(actions[i], json_input[hands[i]][-3:],hands_frames_retilineo, bones_[i]) - + elif(json_input[hands[i]][0] == "senoidal"): + orientation, direction, radius, laps = json_input[hands[i]][1:5] + endFrame = circular_or_semiCircular(pose, orientation, direction, radius, laps, 5) + generationConfigurations(actions[i], json_input[hands[i]][-3:], [endFrame], bones_[i]) + # Função que inicia a configuração da face -def configureFace(): +def configureFace(): global endFrame if(json_input["facialExp"] != []): # Set face - faceConfiguration(json_input["facialExp"], [endFrame/4], util.faceBonesConf) + faceConfiguration(json_input["facialExp"], [endFrame/4], util.faceBonesConf) # Default Pose print(endFrame) -poseDefault([1, endFrame+15], util.allBones) +poseDefault([1, endFrame + 15], util.allBones) configureHands() configureFace() -util.render_sign(json_input["userId"], json_input["signName"], 1, endFrame + 25) \ No newline at end of file +util.render_sign(json_input["userId"], json_input["signName"], 1, endFrame + 25) diff --git a/moves.py b/moves.py index 8e68364..de656fd 100644 --- a/moves.py +++ b/moves.py @@ -1,4 +1,5 @@ # -*- coding: UTF-8 -*- + import math def circular_or_semiCircular(pose, orientation, direction, radius, laps, intensity = 5, initialFrame = 18, turn = None): @@ -7,7 +8,7 @@ def circular_or_semiCircular(pose, orientation, direction, radius, laps, intensi if(direction == 'horario'): endFrame = moves.locationCircular(center, radius, 1, 0, 2, pose, 0, laps, intensity, initialFrame,turn) else: - endFrame = moves.locationCircular(center, radius, 0, 1, 2, pose, 0, laps, intensity, initialFrame,turn) + endFrame = moves.locationCircular(center, radius, 0, 1, 2, pose, 0, laps, intensity, initialFrame,turn) elif(orientation == 'paralelo'): if(direction == 'horario'): endFrame = moves.locationCircular(center, radius, 1, 2, 0, pose, 0, laps, intensity, initialFrame,turn) @@ -20,6 +21,11 @@ def circular_or_semiCircular(pose, orientation, direction, radius, laps, intensi endFrame = moves.locationCircular(center, radius, 0, 2, 1, pose, 0, laps, intensity, initialFrame,turn) return endFrame +# center[3]: float vector (posição xyz centro) +# radius: float (distancia do centro) +# i_axis: int (indice do eixo i [0 | 1 | 2]) +# j_axis: int (indice do eixo j [0 | 1 | 2]) +# k_axis: int (indice do eixo k [0 | 1 | 2]) def locationCircular(center, radius, i_axis, j_axis, k_axis, pose, initialPosition, laps, frameJump = 5, initialFrame = 18, turn = None): sqrt22 = radius * (math.sqrt(2) / 2) rad2 = (radius/2) @@ -71,14 +77,14 @@ def locationCircular(center, radius, i_axis, j_axis, k_axis, pose, initialPositi pose.location[k_axis] = center[k_axis] + rad2 pose.keyframe_insert(frame = currentFrame, index = -1, data_path = 'location') currentFrame += frameJump - + if ((l % 8) == 4): pose.location[i_axis] = center[i_axis] - radius pose.location[j_axis] = center[j_axis] - pose.location[k_axis] = center[k_axis] + pose.location[k_axis] = center[k_axis] pose.keyframe_insert(frame = currentFrame, index = -1, data_path = 'location') currentFrame += frameJump - + if ((l % 8) == 5): pose.location[i_axis] = center[i_axis] - sqrt22 pose.location[j_axis] = center[j_axis] - sqrt22 @@ -93,7 +99,7 @@ def locationCircular(center, radius, i_axis, j_axis, k_axis, pose, initialPositi pose.location[k_axis] = center[k_axis] - rad2 pose.keyframe_insert(frame = currentFrame, index = -1, data_path = 'location') currentFrame += frameJump - + if ((l % 8) == 6): pose.location[i_axis] = center[i_axis] pose.location[j_axis] = center[j_axis] - radius @@ -106,7 +112,7 @@ def locationCircular(center, radius, i_axis, j_axis, k_axis, pose, initialPositi pose.location[k_axis] = center[k_axis] - sqrt22 pose.keyframe_insert(frame = currentFrame, index = -1, data_path = 'location') currentFrame += frameJump - + if ((l % 8) == 7): pose.location[i_axis] = center[i_axis] + sqrt22 pose.location[j_axis] = center[j_axis] - sqrt22 @@ -121,11 +127,9 @@ def locationCircular(center, radius, i_axis, j_axis, k_axis, pose, initialPositi pose.location[k_axis] = center[k_axis] - rad2 pose.keyframe_insert(frame = currentFrame, index = -1, data_path = 'location') currentFrame += frameJump - currentFrame -= frameJump + currentFrame -= frameJump return currentFrame - -# testing . . . def locationHelicoidal(center, startRadius, incRadius, x, y, z, currentLoc, laps, frameJump): sqrt22 = radius * math.sqrt(2) / 2 allLaps = math.floor(8 * laps) + 1 @@ -191,11 +195,7 @@ def locationHelicoidal(center, startRadius, incRadius, x, y, z, currentLoc, laps bpy.context.scene.frame_end -= frameJump -# testing . . . def locationSenoidal(obj): - obj.location = [0, 0, 0] - bpy.context.scene.frame_start = 1 - bpy.context.scene.frame_end = 1 seno = 0 waveHeight = 5.0 wave = 5 @@ -208,4 +208,3 @@ def locationSenoidal(obj): if (i % 10 == 0): obj.keyframe_insert(frame = bpy.context.scene.frame_end, index = -1, data_path = 'location') bpy.context.scene.frame_end += 1 - \ No newline at end of file diff --git a/util.py b/util.py index 25b8e21..66bd6e9 100644 --- a/util.py +++ b/util.py @@ -2,22 +2,45 @@ import bpy import math +import sys +import os -bones = ["BnMao.R", "BnMao.L"] armature = bpy.context.scene.objects.get('Armature.001') + +bones = ["BnMao.R", "BnMao.L"] + +# Vetor com indices de cada bone do lado direito rightBonesConf = [1, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66] + +# Vetor com indices de cada bone do lado esquerdo leftBonesConf = [0, 43, 44, 45, 46, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82] + +# Vetor com indices de cada bone da face faceBonesConf =[15, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47] + +# Vetor com indices de todos os bones allBones = list(range(len(armature.pose.bones))) +def printStackTrace(filename): + print("\n[Exception]\n File: %s\n Name: %s\n Line: %s\n Type: %s\n Message: %s\n[Exception]\n" % ( + os.path.basename(filename), # os.path.basename(sys.exc_info()[2].tb_frame.f_code.co_filename), + sys.exc_info()[2].tb_frame.f_code.co_name, + sys.exc_info()[2].tb_lineno, + sys.exc_info()[0].__name__, + sys.exc_info()[1], + ) + ) + +# Função que limpa todos os keyframes e define a quantidade de frames def erase_all_keyframes(): for i in bpy.data.objects: i.animation_data_clear() bpy.context.scene.frame_start = 1 bpy.context.scene.frame_current = bpy.context.scene.frame_start bpy.context.scene.frame_end = bpy.context.scene.frame_start - + def outconf(): + erase_all_keyframes() bpy.context.scene.render.resolution_x = 640 bpy.context.scene.render.resolution_y = 480 bpy.context.scene.render.resolution_percentage = 100 @@ -25,16 +48,38 @@ def outconf(): bpy.context.scene.render.ffmpeg.format = 'MPEG4' bpy.context.scene.render.ffmpeg.codec = 'H264' # bpy.context.scene.render.filepath = '/tmp/' - + +def file_rename(filename): + from shutil import move + newFilename = "" + isValidChar = True + for char in reversed(filename): + if (isValidChar == True): + newFilename += char + if (char == '_'): + isValidChar = True + elif (char == '.'): + isValidChar = False + if (len(filename) != len(newFilename)): + try: + move(filename, newFilename[::-1]) + return 1 + except Exception as e: + printStackTrace(__file__) + return 0 + return 0 + def render_sign(userId, signName, beginFrame, endFrame): bpy.context.scene.render.filepath = "//users//"+ str(userId)+ "//"+ signName + "_" bpy.context.scene.frame_start = beginFrame bpy.context.scene.frame_end = endFrame - bpy.ops.render.render(animation = True, write_still = False, layer = "", scene = "") + outFilename = (bpy.context.scene.render.filepath + "%0.4i-%0.4i.mp4" % (bpy.context.scene.frame_start, bpy.context.scene.frame_end)) + bpy.ops.render.render(animation = True, write_still = False, layer = "", scene = "") + file_rename(outFilename) bpy.ops.wm.quit_blender() # Função que recupera o frame final do movimento -def get_endFrame(json_input,hands_frames_retilineo): +def get_endFrame(json_input,hands_frames_retilineo): endsFrame = [18] if(json_input["rightHand"] != []): if(json_input["rightHand"][0] == "circular"): @@ -44,10 +89,10 @@ def get_endFrame(json_input,hands_frames_retilineo): elif(json_input["rightHand"][0] == "retilineo"): endsFrame.append(max(hands_frames_retilineo)) if(json_input["leftHand"] != []): - if(json_input["leftHand"][0] == "circular"): + if(json_input["leftHand"][0] == "circular"): endsFrame.append(int(json_input["leftHand"][4]*8*5+18)) elif(json_input["leftHand"][0] == "semicircular"): endsFrame.append(int(json_input["rightHand"][4]*5*5+18)) elif(json_input["rightHand"][0] == "retilineo"): endsFrame.append(max(hands_frames_retilineo)) - return(max(endsFrame)) + return(max(endsFrame)) -- libgit2 0.21.2