Commit bb4c6ded21679d1b5fece7e665174ed4a6414c1c
1 parent
8425c440
Exists in
master
Implementa expressão facial dinâmica
Showing
6 changed files
with
256 additions
and
99 deletions
Show diff stats
Makefile
| @@ -7,7 +7,8 @@ JSON_ALL = \ | @@ -7,7 +7,8 @@ JSON_ALL = \ | ||
| 7 | { \ | 7 | { \ |
| 8 | "facial": { \ | 8 | "facial": { \ |
| 9 | "expressao": 0..21, \ | 9 | "expressao": 0..21, \ |
| 10 | - "velocidade": "lento|normal|rapido" \ | 10 | + "transicao": "lento|normal|rapido", \ |
| 11 | + "duracao": "lento|normal|rapido" \ | ||
| 11 | }, \ | 12 | }, \ |
| 12 | "mao_esquerda": { \ | 13 | "mao_esquerda": { \ |
| 13 | "circular": { \ | 14 | "circular": { \ |
| @@ -102,28 +103,39 @@ JSON = \ | @@ -102,28 +103,39 @@ JSON = \ | ||
| 102 | '{ \ | 103 | '{ \ |
| 103 | "userId": "lavid", \ | 104 | "userId": "lavid", \ |
| 104 | "sinal": "Modelo JSON 2", \ | 105 | "sinal": "Modelo JSON 2", \ |
| 105 | - "ex_interpolacao": "lento|normal|rapido", \ | ||
| 106 | "interpolacao": "normal", \ | 106 | "interpolacao": "normal", \ |
| 107 | "movimentos": [ \ | 107 | "movimentos": [ \ |
| 108 | { \ | 108 | { \ |
| 109 | "facial": { \ | 109 | "facial": { \ |
| 110 | - "expressao": 21, \ | ||
| 111 | - "velocidade": "lento|normal|rapido" \ | 110 | + "expressao": 20, \ |
| 111 | + "transicao": "normal", \ | ||
| 112 | + "duracao": "normal" \ | ||
| 112 | }, \ | 113 | }, \ |
| 113 | "mao_esquerda": { \ | 114 | "mao_esquerda": { \ |
| 114 | "circular": { \ | 115 | "circular": { \ |
| 115 | "plano": "esquerda-cima", \ | 116 | "plano": "esquerda-cima", \ |
| 116 | "raio": "pequeno", \ | 117 | "raio": "pequeno", \ |
| 117 | - "velocidade": "lento", \ | 118 | + "velocidade": "normal", \ |
| 118 | "lado_oposto": false, \ | 119 | "lado_oposto": false, \ |
| 119 | "sentido_inverso": false, \ | 120 | "sentido_inverso": false, \ |
| 120 | "articulacao": 124, \ | 121 | "articulacao": 124, \ |
| 121 | - "configuracao": 129, \ | 122 | + "configuracao": 60, \ |
| 122 | "orientacao": 142 \ | 123 | "orientacao": 142 \ |
| 123 | } \ | 124 | } \ |
| 124 | }, \ | 125 | }, \ |
| 125 | "mao_direita": { \ | 126 | "mao_direita": { \ |
| 126 | } \ | 127 | } \ |
| 128 | + }, \ | ||
| 129 | + { \ | ||
| 130 | + "facial": { \ | ||
| 131 | + "expressao": 21, \ | ||
| 132 | + "transicao": "normal", \ | ||
| 133 | + "duracao": "normal" \ | ||
| 134 | + }, \ | ||
| 135 | + "mao_esquerda": { \ | ||
| 136 | + }, \ | ||
| 137 | + "mao_direita": { \ | ||
| 138 | + } \ | ||
| 127 | } \ | 139 | } \ |
| 128 | ] \ | 140 | ] \ |
| 129 | }' | 141 | }' |
controller.py
| @@ -18,6 +18,6 @@ try: | @@ -18,6 +18,6 @@ try: | ||
| 18 | # result = subprocess.call(['blender', '-b', blend_path, '-P', main_path, '--', sys.argv[1]], stdout = open('bpy.log', 'w')) | 18 | # result = subprocess.call(['blender', '-b', blend_path, '-P', main_path, '--', sys.argv[1]], stdout = open('bpy.log', 'w')) |
| 19 | result = subprocess.call(['blender', '-b', blend_path, '-P', main_path, '--', sys.argv[1]]) | 19 | result = subprocess.call(['blender', '-b', blend_path, '-P', main_path, '--', sys.argv[1]]) |
| 20 | except: | 20 | except: |
| 21 | - result = pyutil.printStackTrace(__file__) | 21 | + result = pyutil.print_stack_trace(__file__) |
| 22 | 22 | ||
| 23 | exit(result) | 23 | exit(result) |
| @@ -0,0 +1,123 @@ | @@ -0,0 +1,123 @@ | ||
| 1 | +# -*- coding: UTF-8 -*- | ||
| 2 | + | ||
| 3 | +import bpy | ||
| 4 | +import util | ||
| 5 | + | ||
| 6 | +library_name = '07_facial' | ||
| 7 | + | ||
| 8 | +# duracao na posicao selecionada | ||
| 9 | +dict_duration = { | ||
| 10 | + 'lento': 15, | ||
| 11 | + 'normal': 10, | ||
| 12 | + 'rapido': 5 | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +# tempo de entrada e saida na posicao selecionada | ||
| 16 | +dict_transition = { | ||
| 17 | + 'lento': 15, | ||
| 18 | + 'normal': 10, | ||
| 19 | + 'rapido': 5 | ||
| 20 | +} | ||
| 21 | + | ||
| 22 | +# marcador global da linha do tempo exclusivo para expressao facial | ||
| 23 | +timeline_facial = 0 | ||
| 24 | + | ||
| 25 | +# insere keyframes aos bones selecionados anteriormente e passados como parametro | ||
| 26 | +def keyframe_insert(current_frame = 0, pose_bones = bpy.context.object.pose.bones, keyframe_types = ['location', 'rotation_quaternion']): | ||
| 27 | + # verifica se existe apenas um bone | ||
| 28 | + if (isinstance(pose_bones, int) or isinstance(pose_bones, str)): | ||
| 29 | + # verifica se existe apenas um tipo de insercao de keyframe | ||
| 30 | + if (isinstance(keyframe_types, str)): | ||
| 31 | + bpy.context.object.pose.bones[pose_bones].keyframe_insert(index = -1, frame = current_frame, group = bpy.context.object.pose.bones[pose_bones].name, data_path = keyframe_types) | ||
| 32 | + # verifica se existe mais de um tipo de insercao de keyframe | ||
| 33 | + elif (isinstance(keyframe_types, list)): | ||
| 34 | + for keyframe_type in keyframe_types: | ||
| 35 | + bpy.context.object.pose.bones[bones].keyframe_insert(index = -1, frame = current_frame, group = bpy.context.object.pose.bones[pose_bones].name, data_path = keyframe_type) | ||
| 36 | + # verifica se existe mais de um bone | ||
| 37 | + elif (isinstance(pose_bones, list)): | ||
| 38 | + for bone in pose_bones: | ||
| 39 | + # verifica se existe apenas um tipo de insercao de keyframe | ||
| 40 | + if (isinstance(keyframe_types, str)): | ||
| 41 | + bpy.context.object.pose.bones[bone].keyframe_insert(index = -1, frame = current_frame, group = bpy.context.object.pose.bones[bone].name, data_path = keyframe_types) | ||
| 42 | + # verifica se existe mais de um tipo de insercao de keyframe | ||
| 43 | + elif (isinstance(keyframe_types, list)): | ||
| 44 | + for keyframe_type in keyframe_types: | ||
| 45 | + bpy.context.object.pose.bones[bone].keyframe_insert(index = -1, frame = current_frame, group = bpy.context.object.pose.bones[bone].name, data_path = keyframe_type) | ||
| 46 | + return | ||
| 47 | + | ||
| 48 | +# aplica biblioteca(s) de pose(s) e seu respectivo indice | ||
| 49 | +def apply_pose(index = 0, pose_library = list(bpy.data.actions)): | ||
| 50 | + # verifica se deve aplicar apenas uma biblioteca | ||
| 51 | + if (isinstance(pose_library, int) or isinstance(pose_library, str)): | ||
| 52 | + # verifica biblioteca fake_user | ||
| 53 | + if (bpy.data.actions[pose_library].use_fake_user): | ||
| 54 | + bpy.context.object.pose_library = bpy.data.actions[pose_library] | ||
| 55 | + bpy.ops.poselib.apply_pose(pose_index = index) | ||
| 56 | + # verifica se deve aplicar mais de uma biblioteca | ||
| 57 | + elif (isinstance(pose_library, list)): | ||
| 58 | + for library in pose_library: | ||
| 59 | + # verifica biblioteca fake_user | ||
| 60 | + if (library.use_fake_user): | ||
| 61 | + bpy.context.object.pose_library = library | ||
| 62 | + bpy.ops.poselib.apply_pose(pose_index = index) | ||
| 63 | + bpy.context.object.pose_library = None | ||
| 64 | + return | ||
| 65 | + | ||
| 66 | +# consolida o movimento (faz insercao dos keyframes) e incrementa a timeline | ||
| 67 | +def set_expression(index, frame_duration = dict_duration['normal'], frame_transition = 0): | ||
| 68 | + global timeline_facial | ||
| 69 | + global library_name | ||
| 70 | + bones_facial = util.dict_bones[library_name] | ||
| 71 | + util.select_bones(bones_facial) | ||
| 72 | + # TODO separar bones 'location' e 'rotation_quaternion' | ||
| 73 | + keyframe_insert(timeline_facial, bones_facial, ['location', 'rotation_quaternion']) | ||
| 74 | + apply_pose(index, library_name) | ||
| 75 | + timeline_facial += frame_transition | ||
| 76 | + keyframe_insert(timeline_facial, bones_facial, ['location', 'rotation_quaternion']) | ||
| 77 | + timeline_facial += frame_duration | ||
| 78 | + keyframe_insert(timeline_facial, bones_facial, ['location', 'rotation_quaternion']) | ||
| 79 | + timeline_facial += frame_transition | ||
| 80 | + util.deselect_bones(bones_facial) | ||
| 81 | + return timeline_facial | ||
| 82 | + | ||
| 83 | +# decodifica objeto JSON | ||
| 84 | +def decode_expression(js_facial, initial_interpolation = dict_duration['normal']): | ||
| 85 | + global dict_duration | ||
| 86 | + global dict_transition | ||
| 87 | + index = js_facial['expressao'] | ||
| 88 | + frame_duration = dict_duration[js_facial['duracao']] | ||
| 89 | + frame_transition = dict_duration[js_facial['transicao']] | ||
| 90 | + # insere o primeiro keyframe | ||
| 91 | + if (timeline_facial == 0): | ||
| 92 | + set_expression(0, initial_interpolation) | ||
| 93 | + set_expression(index, frame_duration, frame_transition) | ||
| 94 | + set_expression(0, frame_duration) | ||
| 95 | + return timeline_facial | ||
| 96 | + | ||
| 97 | +""" | ||
| 98 | +# unit test | ||
| 99 | +def main(): | ||
| 100 | + import random | ||
| 101 | + interpolation_start = 20 | ||
| 102 | + interpolation_end = 20 | ||
| 103 | + pose_max_range = round(bpy.data.actions[library_name].frame_range[1]) | ||
| 104 | + | ||
| 105 | + util.delete_all_keyframes() | ||
| 106 | + apply_pose(0, library_name) | ||
| 107 | + | ||
| 108 | + js_facial = {"expressao": random.randint(0, pose_max_range), "transicao": 'normal', "duracao": 'normal'} | ||
| 109 | + print('facial expression %d current frame:' % (js_facial['expressao']), decode_expression(js_facial)) | ||
| 110 | + | ||
| 111 | + js_facial = {"expressao": random.randint(0, pose_max_range), "transicao": 'normal', "duracao": 'normal'} | ||
| 112 | + print('facial expression %d current frame:' % (js_facial['expressao']), decode_expression(js_facial)) | ||
| 113 | + | ||
| 114 | + #for i in range(0, pose_max_range + 1): | ||
| 115 | + # js_facial = {"expressao": i, "transicao": 'normal', "duracao": 'normal'} | ||
| 116 | + # print('facial expression %d current frame:' % (js_facial['expressao']), decode_expression(js_facial)) | ||
| 117 | + | ||
| 118 | + bpy.context.scene.frame_end = timeline_facial + interpolation_end | ||
| 119 | + bpy.ops.screen.animation_play(reverse = False) | ||
| 120 | + | ||
| 121 | +if __name__ == "__main__": | ||
| 122 | + main() | ||
| 123 | +""" | ||
| 0 | \ No newline at end of file | 124 | \ No newline at end of file |
libras.py
| @@ -18,9 +18,16 @@ sys.path.insert(0, getcwd) | @@ -18,9 +18,16 @@ sys.path.insert(0, getcwd) | ||
| 18 | import util | 18 | import util |
| 19 | import moves | 19 | import moves |
| 20 | import pyutil | 20 | import pyutil |
| 21 | +import facial | ||
| 21 | 22 | ||
| 22 | # intervalos de interpolacao dos keyframes | 23 | # intervalos de interpolacao dos keyframes |
| 23 | -interpolation = {'inicial': 20, 'lento': 5, 'normal': 10, 'rapido': 15, 'final': 20} | 24 | +dict_interpolation = { |
| 25 | + 'inicial': 20, | ||
| 26 | + 'lento': 5, | ||
| 27 | + 'normal': 10, | ||
| 28 | + 'rapido': 15, | ||
| 29 | + 'final': 20 | ||
| 30 | +} | ||
| 24 | 31 | ||
| 25 | def insert_keyframe_pose_default(current_frame = 0, frame_jump = 0, pose_bones = bpy.context.object.pose.bones, types_keyframe = ['location', 'rotation_quaternion']): | 32 | def insert_keyframe_pose_default(current_frame = 0, frame_jump = 0, pose_bones = bpy.context.object.pose.bones, types_keyframe = ['location', 'rotation_quaternion']): |
| 26 | for obj in (pose_bones): | 33 | for obj in (pose_bones): |
| @@ -41,17 +48,20 @@ def pose_default(current_frame = 0, frame_jump = 0, actions = bpy.data.actions): | @@ -41,17 +48,20 @@ def pose_default(current_frame = 0, frame_jump = 0, actions = bpy.data.actions): | ||
| 41 | 48 | ||
| 42 | def decode_circular_semicircular(js_movement, current_frame, frame_jump, is_right_hand, is_semicircular): | 49 | def decode_circular_semicircular(js_movement, current_frame, frame_jump, is_right_hand, is_semicircular): |
| 43 | # const | 50 | # const |
| 44 | - obj_raio = {'pequeno': 0.5, 'normal': 1.0, 'grande': 1.5} | ||
| 45 | - obj_periodo = {'lento': 55, 'normal': 45, 'rapido': 35} | 51 | + dict_ray = {'pequeno': 0.5, 'normal': 1.0, 'grande': 1.5} |
| 52 | + dict_period = {'lento': 55, 'normal': 45, 'rapido': 35} | ||
| 46 | # decodificar valores | 53 | # decodificar valores |
| 47 | - raio = obj_raio[js_movement['raio']] | ||
| 48 | - periodo = obj_periodo[js_movement['velocidade']] | 54 | + ray = dict_ray[js_movement['raio']] |
| 55 | + period = dict_period[js_movement['velocidade']] | ||
| 56 | + print('setar articulacao:', js_movement['articulacao']) | ||
| 57 | + print('setar configuracao:', js_movement['configuracao']) | ||
| 58 | + print('setar orientacao:', js_movement['orientacao']) | ||
| 49 | # diminuir a velocidade | 59 | # diminuir a velocidade |
| 50 | if (js_movement['velocidade'] == 'lento'): | 60 | if (js_movement['velocidade'] == 'lento'): |
| 51 | - periodo += 10 | 61 | + period += 10 |
| 52 | # aumentar a velocidade | 62 | # aumentar a velocidade |
| 53 | elif (js_movement['velocidade'] == 'rapido'): | 63 | elif (js_movement['velocidade'] == 'rapido'): |
| 54 | - periodo -= 10 | 64 | + period -= 10 |
| 55 | # definir eixos do movimento | 65 | # definir eixos do movimento |
| 56 | if (js_movement['plano'] == 'frente-esquerda'): | 66 | if (js_movement['plano'] == 'frente-esquerda'): |
| 57 | x, y = 2, 0 | 67 | x, y = 2, 0 |
| @@ -61,11 +71,11 @@ def decode_circular_semicircular(js_movement, current_frame, frame_jump, is_righ | @@ -61,11 +71,11 @@ def decode_circular_semicircular(js_movement, current_frame, frame_jump, is_righ | ||
| 61 | x, y = 0, 1 | 71 | x, y = 0, 1 |
| 62 | # mao usada (direita/esquerda) | 72 | # mao usada (direita/esquerda) |
| 63 | if (is_right_hand): | 73 | if (is_right_hand): |
| 64 | - ik = bpy.context.object.pose.bones[1] | 74 | + ik = bpy.context.object.pose.bones['ik_FK.R'] |
| 65 | else: | 75 | else: |
| 66 | - ik = bpy.context.object.pose.bones[0] | 76 | + ik = bpy.context.object.pose.bones['ik_FK.L'] |
| 67 | current_frame = insert_keyframe_pose_default(current_frame, frame_jump, [ik], ['location']) | 77 | current_frame = insert_keyframe_pose_default(current_frame, frame_jump, [ik], ['location']) |
| 68 | - current_frame = moves.circular(ik, current_frame + frame_jump, raio, periodo, x, y, js_movement['lado_oposto'], js_movement['sentido_inverso'], is_semicircular) | 78 | + current_frame = moves.circular(ik, current_frame + frame_jump, ray, period, x, y, js_movement['lado_oposto'], js_movement['sentido_inverso'], is_semicircular) |
| 69 | return current_frame | 79 | return current_frame |
| 70 | 80 | ||
| 71 | def decode_hand_mov(current_frame, frame_jump, js_mao, is_right_hand): | 81 | def decode_hand_mov(current_frame, frame_jump, js_mao, is_right_hand): |
| @@ -79,13 +89,14 @@ def decode_hand_mov(current_frame, frame_jump, js_mao, is_right_hand): | @@ -79,13 +89,14 @@ def decode_hand_mov(current_frame, frame_jump, js_mao, is_right_hand): | ||
| 79 | current_frame = decode_circular_semicircular(js_mao[movement_name], current_frame, frame_jump, is_right_hand, True) | 89 | current_frame = decode_circular_semicircular(js_mao[movement_name], current_frame, frame_jump, is_right_hand, True) |
| 80 | return current_frame + frame_jump | 90 | return current_frame + frame_jump |
| 81 | 91 | ||
| 92 | +""" | ||
| 82 | # Funcao responsavel por setar pose padrao | 93 | # Funcao responsavel por setar pose padrao |
| 83 | def poseDefault(json_input, positionFrames, collisionFlag = False): | 94 | def poseDefault(json_input, positionFrames, collisionFlag = False): |
| 84 | handDefaultParam = [0, 0, 0] | 95 | handDefaultParam = [0, 0, 0] |
| 85 | util.setPose(util.right_hand_actions, handDefaultParam, positionFrames, util.rightBonesConf, collisionFlag) | 96 | util.setPose(util.right_hand_actions, handDefaultParam, positionFrames, util.rightBonesConf, collisionFlag) |
| 86 | if(json_input["leftHand"] != []): | 97 | if(json_input["leftHand"] != []): |
| 87 | util.setPose(util.left_hand_actions, handDefaultParam, positionFrames, util.leftBonesConf, collisionFlag) | 98 | util.setPose(util.left_hand_actions, handDefaultParam, positionFrames, util.leftBonesConf, collisionFlag) |
| 88 | - #setFaceConfiguration([0], positionFrames, util.faceBonesConf) | 99 | + setFaceConfiguration([0], positionFrames, util.faceBonesConf) |
| 89 | 100 | ||
| 90 | # Funcao responsavel por setar as configuracoes das maos | 101 | # Funcao responsavel por setar as configuracoes das maos |
| 91 | def setHandConfiguration(actions, handParam, positionFrames, bones): | 102 | def setHandConfiguration(actions, handParam, positionFrames, bones): |
| @@ -123,61 +134,66 @@ def configureHands(endFrame): | @@ -123,61 +134,66 @@ def configureHands(endFrame): | ||
| 123 | setHandConfiguration(actions[i], handParam, [endFrame], bones_[i]) | 134 | setHandConfiguration(actions[i], handParam, [endFrame], bones_[i]) |
| 124 | elif(move == "contato"): | 135 | elif(move == "contato"): |
| 125 | endFrame = moves.contato(actions[i], json_input[hands[i]], bones_[i], pose) | 136 | endFrame = moves.contato(actions[i], json_input[hands[i]], bones_[i], pose) |
| 126 | - | ||
| 127 | -# Funcao que inicia a configuracao da face | ||
| 128 | -def setFacialExpr(a, b): | ||
| 129 | - pass | ||
| 130 | - #if(json_input["facialExp"] != []): | ||
| 131 | - # setFaceConfiguration(json_input["facialExp"], [endFrame/4], util.faceBonesConf) | 137 | +""" |
| 132 | 138 | ||
| 133 | def main(): | 139 | def main(): |
| 140 | + util.delete_all_keyframes() | ||
| 134 | util.configure_output() | 141 | util.configure_output() |
| 135 | bpy.context.scene.animation_data_create() | 142 | bpy.context.scene.animation_data_create() |
| 136 | 143 | ||
| 137 | try: | 144 | try: |
| 138 | js_input = json.loads(sys.argv[6]) | 145 | js_input = json.loads(sys.argv[6]) |
| 139 | js_movimentos = js_input['movimentos'] | 146 | js_movimentos = js_input['movimentos'] |
| 140 | - frame_jump = interpolation[js_input['interpolacao']] | 147 | + frame_jump = dict_interpolation[js_input['interpolacao']] |
| 141 | 148 | ||
| 142 | endFrame = pose_default(0) | 149 | endFrame = pose_default(0) |
| 143 | - facial_frame = 0 | ||
| 144 | mao_esquerda_frame = 0 | 150 | mao_esquerda_frame = 0 |
| 145 | mao_direita_frame = 0 | 151 | mao_direita_frame = 0 |
| 146 | 152 | ||
| 147 | - # setar pose padrao inicial em todos os bones ('location' e 'rotation_quaternion') | ||
| 148 | - endFrame += pose_default(interpolation['inicial']) | 153 | + # pose padrao inicial em todos os bones ('location' e 'rotation_quaternion') |
| 154 | + endFrame += pose_default(dict_interpolation['inicial']) | ||
| 149 | 155 | ||
| 150 | for i in range(0, len(js_movimentos)): | 156 | for i in range(0, len(js_movimentos)): |
| 151 | - | ||
| 152 | - js_facial = js_movimentos[i]['facial'] | ||
| 153 | - | ||
| 154 | - if (js_facial != {}): | ||
| 155 | - setFacialExpr(js_facial['expressao'], js_facial['velocidade']) | 157 | + # tenta decodificar objetos JSON |
| 158 | + try: | ||
| 159 | + js_facial = js_movimentos[i]['facial'] | ||
| 160 | + except: | ||
| 161 | + js_facial = {} | ||
| 162 | + try: | ||
| 163 | + js_mao_esquerda = js_movimentos[i]['mao_esquerda'] | ||
| 164 | + except: | ||
| 165 | + js_mao_esquerda = {} | ||
| 166 | + try: | ||
| 167 | + js_mao_direita = js_movimentos[i]['mao_direita'] | ||
| 168 | + except: | ||
| 169 | + js_mao_direita = {} | ||
| 170 | + | ||
| 171 | + # faz tratamento dos objetos | ||
| 172 | + if (js_facial == {}): | ||
| 173 | + pyutil.log("<Vazio> js_movimentos[%d] >> Exp facial" % (i)) | ||
| 174 | + facial.set_expression(0, facial.timeline_facial + frame_jump) | ||
| 156 | else: | 175 | else: |
| 157 | - pyutil.log("<Vazio> Expressao Facial %d" % (i)) | 176 | + facial.decode_expression(js_facial) |
| 158 | 177 | ||
| 159 | - js_mao_esquerda = js_movimentos[i]['mao_esquerda'] | ||
| 160 | - if (js_mao_esquerda != {}): | ||
| 161 | - mao_esquerda_frame += decode_hand_mov(mao_esquerda_frame, frame_jump, js_mao_esquerda, False) | 178 | + if (js_mao_esquerda == {}): |
| 179 | + pyutil.log("<Vazio> js_movimentos[%d] >> Mao esquerda" % (i)) | ||
| 180 | + # TODO posicionar mao esquerda na lateral do corpo | ||
| 162 | else: | 181 | else: |
| 163 | - pyutil.log("<Vazio> mov %d Mao esquerda" % (i)) | 182 | + mao_esquerda_frame += decode_hand_mov(mao_esquerda_frame, frame_jump, js_mao_esquerda, False) |
| 164 | 183 | ||
| 165 | - js_mao_direita = js_movimentos[i]['mao_direita'] | ||
| 166 | - if (js_mao_direita != {}): | ||
| 167 | - mao_direita_frame += decode_hand_mov(mao_direita_frame, frame_jump, js_mao_direita, True) | 184 | + if (js_mao_direita == {}): |
| 185 | + pyutil.log("<Vazio> js_movimentos[%d] >> Mao direita" % (i)) | ||
| 186 | + # TODO posicionar mao direita na lateral do corpo | ||
| 168 | else: | 187 | else: |
| 169 | - pyutil.log("<Vazio> mov %d Mao direita" % (i)) | 188 | + mao_direita_frame += decode_hand_mov(mao_direita_frame, frame_jump, js_mao_direita, True) |
| 170 | 189 | ||
| 171 | - endFrame = max(facial_frame, mao_esquerda_frame, mao_direita_frame) | 190 | + endFrame = max(facial.timeline_facial, mao_esquerda_frame, mao_direita_frame) |
| 172 | endFrame += frame_jump | 191 | endFrame += frame_jump |
| 173 | 192 | ||
| 174 | # setar pose padrao final em todos os bones (location e rotation) | 193 | # setar pose padrao final em todos os bones (location e rotation) |
| 175 | - #endFrame += pose_default(endFrame + interpolation['final']) | ||
| 176 | - endFrame = insert_keyframe_pose_default(endFrame, frame_jump) | ||
| 177 | - endFrame += interpolation['final'] | ||
| 178 | - | ||
| 179 | - # Sugestao: Alguma forma de uniformizar o calculo do endFrame (atualizado aqui e no movimento circular) | ||
| 180 | - #initialFrame = 15 | 194 | + #endFrame += pose_default(endFrame + dict_interpolation['final']) |
| 195 | + #endFrame = insert_keyframe_pose_default(endFrame, frame_jump) | ||
| 196 | + #endFrame += dict_interpolation['final'] | ||
| 181 | #endFrame = util.get_endFrame(js_input, util.hands_frames_retilineo) | 197 | #endFrame = util.get_endFrame(js_input, util.hands_frames_retilineo) |
| 182 | #poseDefault([1]) | 198 | #poseDefault([1]) |
| 183 | #configureHands(endFrame) | 199 | #configureHands(endFrame) |
| @@ -187,7 +203,7 @@ def main(): | @@ -187,7 +203,7 @@ def main(): | ||
| 187 | util.render_sign(js_input["userId"], js_input["sinal"], endFrame) | 203 | util.render_sign(js_input["userId"], js_input["sinal"], endFrame) |
| 188 | 204 | ||
| 189 | except: | 205 | except: |
| 190 | - pyutil.printStackTrace(__file__) | 206 | + pyutil.print_stack_trace(__file__) |
| 191 | raise | 207 | raise |
| 192 | 208 | ||
| 193 | if __name__ == "__main__": | 209 | if __name__ == "__main__": |
pyutil.py
| @@ -64,7 +64,7 @@ def test_log(): | @@ -64,7 +64,7 @@ def test_log(): | ||
| 64 | # @def Função para exibir exceção | 64 | # @def Função para exibir exceção |
| 65 | # @param string deve ser passado: "__file__" para identificar em qual arquivo ocorreu a exceção | 65 | # @param string deve ser passado: "__file__" para identificar em qual arquivo ocorreu a exceção |
| 66 | # @return int Retorna 1 | 66 | # @return int Retorna 1 |
| 67 | -def printStackTrace(fromFile): | 67 | +def print_stack_trace(fromFile): |
| 68 | from sys import exc_info | 68 | from sys import exc_info |
| 69 | from os.path import basename | 69 | from os.path import basename |
| 70 | error = "\n File name: %s\n Function name: %s\n Line code: %s\n Type exception: %s\n Message: %s" % ( | 70 | error = "\n File name: %s\n Function name: %s\n Line code: %s\n Type exception: %s\n Message: %s" % ( |
util.py
| @@ -9,23 +9,33 @@ from bmesh_collision import bmesh_check_intersect_objects | @@ -9,23 +9,33 @@ from bmesh_collision import bmesh_check_intersect_objects | ||
| 9 | 9 | ||
| 10 | armature = bpy.context.scene.objects.get('Armature.001') | 10 | armature = bpy.context.scene.objects.get('Armature.001') |
| 11 | 11 | ||
| 12 | +dict_bones = { | ||
| 13 | + "01_conf_direita": ['BnDedo.1.R', 'BnDedo.1.R.006', 'BnDedo.1.R.005', 'BnDedo.1.R.001', 'BnDedo.1.R.008', 'BnDedo.1.R.007', 'BnDedo.1.R.002', 'BnDedo.1.R.010', 'BnDedo.1.R.009', 'BnDedo.1.R.003', 'BnDedo.1.R.012', 'BnDedo.1.R.011', 'BnDedo.1.R.004', 'BnDedo.1.R.014', 'BnDedo.1.R.013'], | ||
| 14 | + "02_conf_esquerda": ['BnDedo.1.L', 'BnDedo.1.L.006', 'BnDedo.1.L.005', 'BnDedo.1.L.001', 'BnDedo.1.L.008', 'BnDedo.1.L.007', 'BnDedo.1.L.002', 'BnDedo.1.L.010', 'BnDedo.1.L.009', 'BnDedo.1.L.003', 'BnDedo.1.L.012', 'BnDedo.1.L.011', 'BnDedo.1.L.004', 'BnDedo.1.L.014', 'BnDedo.1.L.013'], | ||
| 15 | + "03_pa_direita": ['ik_FK.R', 'BnPolyV.R'], | ||
| 16 | + "04_pa_direita": ['ik_FK.R', 'BnPolyV.R'], | ||
| 17 | + "05_orient_direita": ['BnMao.R'], | ||
| 18 | + "06_orient_esquerda": ['BnMao.L'], | ||
| 19 | + "07_facial": ['BnPescoco', 'BnCabeca', 'BnSobrancCentro.L', 'BnSobrancCentro.R', 'BnSobrancLateral.L', 'BnSobrancLateral.R', 'BnPalpebSuper.L', 'BnPalpebInfe.L', 'BnSobrancCentro', 'BnLabioCentroSuper', 'BnBochecha.L', 'BnBochecha.R', 'BnLabioCentroInfer', 'BnBocaCanto.L', 'BnBocaCanto.R', 'BnMandibula', 'BnLingua', 'BnLingua.003', 'BnLingua.001', 'BnLingua.002', 'BnPalpebSuper.R', 'BnPalpebInfe.R', 'BnOlhosMira', 'BnOlhoMira.L', 'BnOlhoMira.R', 'BnOlho.L', 'BnOlho.R'] | ||
| 20 | +} | ||
| 21 | + | ||
| 12 | # Vetor com indices de cada bone do lado direito | 22 | # Vetor com indices de cada bone do lado direito |
| 13 | -rightBonesConf = [1, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66] | 23 | +# rightBonesConf = [1, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66] |
| 14 | 24 | ||
| 15 | # Vetor com indices de cada bone do lado esquerdo | 25 | # Vetor com indices de cada bone do lado esquerdo |
| 16 | -leftBonesConf = [0, 43, 44, 45, 46, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82] | 26 | +# leftBonesConf = [0, 43, 44, 45, 46, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82] |
| 17 | 27 | ||
| 18 | # Vetor com indices de cada bone da face | 28 | # Vetor com indices de cada bone da face |
| 19 | -faceBonesConf = [15, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47] | 29 | +# faceBonesConf = [15, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47] |
| 20 | 30 | ||
| 21 | # Vetor com indices de todos os bones | 31 | # Vetor com indices de todos os bones |
| 22 | -allBones = list(range(len(armature.pose.bones))) | 32 | +# allBones = list(range(len(armature.pose.bones))) |
| 23 | 33 | ||
| 24 | # define a posição dos keyframes | 34 | # define a posição dos keyframes |
| 25 | -hands_default_frames = [15] | 35 | +# hands_default_frames = [15] |
| 26 | 36 | ||
| 27 | # define a posição dos keyframes | 37 | # define a posição dos keyframes |
| 28 | -hands_frames_retilineo = [30, 33] | 38 | +# hands_frames_retilineo = [30, 33] |
| 29 | 39 | ||
| 30 | # Movimento coçar - Índices de poses | 40 | # Movimento coçar - Índices de poses |
| 31 | cocar_mao_aberta_index = 56 | 41 | cocar_mao_aberta_index = 56 |
| @@ -33,7 +43,7 @@ cocar_mao_fechada_index = 24 | @@ -33,7 +43,7 @@ cocar_mao_fechada_index = 24 | ||
| 33 | cocar_orientation_index = 20 | 43 | cocar_orientation_index = 20 |
| 34 | 44 | ||
| 35 | # Action expressão facial | 45 | # Action expressão facial |
| 36 | -facial_expression_id ='07_facial' | 46 | +facial_expression_id = '07_facial' |
| 37 | facial_expression_action = [facial_expression_id] | 47 | facial_expression_action = [facial_expression_id] |
| 38 | 48 | ||
| 39 | # Actions mão direita | 49 | # Actions mão direita |
| @@ -50,26 +60,39 @@ left_hand_actions = [conf_esquerda_id, pa_esquerda_id, orient_esquerda_id] | @@ -50,26 +60,39 @@ left_hand_actions = [conf_esquerda_id, pa_esquerda_id, orient_esquerda_id] | ||
| 50 | 60 | ||
| 51 | last_keyframe_dict = {} | 61 | last_keyframe_dict = {} |
| 52 | 62 | ||
| 53 | -def select_bones(bones = None): | ||
| 54 | - if (isinstance(bones, int)): | 63 | +def select_bones(bones = bpy.context.object.pose.bones): |
| 64 | + if (isinstance(bones, int) or isinstance(bones, str)): | ||
| 55 | bpy.context.object.pose.bones[bones].bone.select = True | 65 | bpy.context.object.pose.bones[bones].bone.select = True |
| 56 | - else: | 66 | + elif (isinstance(bones, list)): |
| 57 | for bone in bones: | 67 | for bone in bones: |
| 58 | bpy.context.object.pose.bones[bone].bone.select = True | 68 | bpy.context.object.pose.bones[bone].bone.select = True |
| 69 | + elif (isinstance(bones, type(bpy.context.object.pose.bones))): | ||
| 70 | + for pose_bone in bones: | ||
| 71 | + pose_bone.bone.select = True | ||
| 72 | + return | ||
| 59 | 73 | ||
| 60 | -def deselect_bones(bones = None): | ||
| 61 | - if (isinstance(bones, int)): | 74 | +def deselect_bones(bones = bpy.context.object.pose.bones): |
| 75 | + if (isinstance(bones, int) or isinstance(bones, str)): | ||
| 62 | bpy.context.object.pose.bones[bones].bone.select = False | 76 | bpy.context.object.pose.bones[bones].bone.select = False |
| 63 | - else: | 77 | + elif (isinstance(bones, list)): |
| 64 | for bone in bones: | 78 | for bone in bones: |
| 65 | bpy.context.object.pose.bones[bone].bone.select = False | 79 | bpy.context.object.pose.bones[bone].bone.select = False |
| 80 | + elif (isinstance(bones, type(bpy.context.object.pose.bones))): | ||
| 81 | + for pose_bone in bones: | ||
| 82 | + pose_bone.bone.select = False | ||
| 83 | + return | ||
| 84 | + | ||
| 85 | +def delete_all_keyframes(): | ||
| 86 | + bpy.context.active_object.animation_data_clear() | ||
| 87 | + for obj in bpy.data.objects: | ||
| 88 | + obj.animation_data_clear() | ||
| 89 | + return | ||
| 66 | 90 | ||
| 67 | # Função responsável por selecionar as pose-libs e setar os frames | 91 | # Função responsável por selecionar as pose-libs e setar os frames |
| 68 | def setPose(actions, parametesConf, positionFrames, bones, collisionFlag = True): | 92 | def setPose(actions, parametesConf, positionFrames, bones, collisionFlag = True): |
| 69 | bpy.ops.object.mode_set(mode = 'OBJECT') | 93 | bpy.ops.object.mode_set(mode = 'OBJECT') |
| 70 | bpy.ops.object.select_all(action="DESELECT") | 94 | bpy.ops.object.select_all(action="DESELECT") |
| 71 | bpy.ops.object.mode_set(mode = 'POSE') | 95 | bpy.ops.object.mode_set(mode = 'POSE') |
| 72 | - | ||
| 73 | for x in range(len(positionFrames)): | 96 | for x in range(len(positionFrames)): |
| 74 | for l in range(len(actions)): | 97 | for l in range(len(actions)): |
| 75 | action = actions[l] | 98 | action = actions[l] |
| @@ -80,7 +103,6 @@ def setPose(actions, parametesConf, positionFrames, bones, collisionFlag = True) | @@ -80,7 +103,6 @@ def setPose(actions, parametesConf, positionFrames, bones, collisionFlag = True) | ||
| 80 | validHandConf = action in [conf_direita_id, conf_esquerda_id] and "BnDedo" in bone.name | 103 | validHandConf = action in [conf_direita_id, conf_esquerda_id] and "BnDedo" in bone.name |
| 81 | validPA = action in [pa_direita_id, pa_esquerda_id] and "ik_FK" in bone.name or "BnPolyV" in bone.name | 104 | validPA = action in [pa_direita_id, pa_esquerda_id] and "ik_FK" in bone.name or "BnPolyV" in bone.name |
| 82 | validO = action in [orient_direita_id, orient_esquerda_id] and "BnMao" in bone.name | 105 | validO = action in [orient_direita_id, orient_esquerda_id] and "BnMao" in bone.name |
| 83 | - | ||
| 84 | if (validHandConf or validPA or validO): | 106 | if (validHandConf or validPA or validO): |
| 85 | keyframe_insert(bone, 'location', positionFrames[x], collisionFlag and validPA, validO) | 107 | keyframe_insert(bone, 'location', positionFrames[x], collisionFlag and validPA, validO) |
| 86 | keyframe_insert(bone, 'rotation_quaternion', positionFrames[x], collisionFlag and validPA, validO) | 108 | keyframe_insert(bone, 'rotation_quaternion', positionFrames[x], collisionFlag and validPA, validO) |
| @@ -90,10 +112,8 @@ def keyframe_insert(bone, path, positionFrame, collisionFlag = True, rotationFla | @@ -90,10 +112,8 @@ def keyframe_insert(bone, path, positionFrame, collisionFlag = True, rotationFla | ||
| 90 | keyframe_id = bone.name + "_" + path | 112 | keyframe_id = bone.name + "_" + path |
| 91 | last_keyframe = last_keyframe_dict[keyframe_id] if keyframe_id in last_keyframe_dict else 0 | 113 | last_keyframe = last_keyframe_dict[keyframe_id] if keyframe_id in last_keyframe_dict else 0 |
| 92 | last_keyframe_dict[keyframe_id] = positionFrame | 114 | last_keyframe_dict[keyframe_id] = positionFrame |
| 93 | - | ||
| 94 | if (rotationFlag and path == "rotation_quaternion"): | 115 | if (rotationFlag and path == "rotation_quaternion"): |
| 95 | checkRotation(bone, positionFrame, last_keyframe) | 116 | checkRotation(bone, positionFrame, last_keyframe) |
| 96 | - | ||
| 97 | if (collisionFlag): | 117 | if (collisionFlag): |
| 98 | checkCollision(bone, path, positionFrame, last_keyframe) | 118 | checkCollision(bone, path, positionFrame, last_keyframe) |
| 99 | 119 | ||
| @@ -114,7 +134,6 @@ def checkRotation(bone, positionFrame, last_keyframe): | @@ -114,7 +134,6 @@ def checkRotation(bone, positionFrame, last_keyframe): | ||
| 114 | isRightHand = ".R" in bone.name | 134 | isRightHand = ".R" in bone.name |
| 115 | resetBnMaoPosition(isRightHand) | 135 | resetBnMaoPosition(isRightHand) |
| 116 | valid_rotation = validate_rotation(bone, positionFrame, last_keyframe) | 136 | valid_rotation = validate_rotation(bone, positionFrame, last_keyframe) |
| 117 | - | ||
| 118 | if (not valid_rotation): | 137 | if (not valid_rotation): |
| 119 | new_rotation = boneRQ.to_quaternion() * (-1) | 138 | new_rotation = boneRQ.to_quaternion() * (-1) |
| 120 | bone.rotation_quaternion = new_rotation | 139 | bone.rotation_quaternion = new_rotation |
| @@ -123,15 +142,12 @@ def checkRotation(bone, positionFrame, last_keyframe): | @@ -123,15 +142,12 @@ def checkRotation(bone, positionFrame, last_keyframe): | ||
| 123 | def checkCollision(bone, path, positionFrame, last_keyframe): | 142 | def checkCollision(bone, path, positionFrame, last_keyframe): |
| 124 | if (last_keyframe == positionFrame): | 143 | if (last_keyframe == positionFrame): |
| 125 | return | 144 | return |
| 126 | - | ||
| 127 | isRightHand = ".R" in bone.name | 145 | isRightHand = ".R" in bone.name |
| 128 | resetIKPosition(isRightHand) | 146 | resetIKPosition(isRightHand) |
| 129 | handCollisionFrame = check_hand_collision(last_keyframe, positionFrame) | 147 | handCollisionFrame = check_hand_collision(last_keyframe, positionFrame) |
| 130 | - | ||
| 131 | if (handCollisionFrame != -1): | 148 | if (handCollisionFrame != -1): |
| 132 | handle_collision(bone, path, positionFrame, handCollisionFrame) | 149 | handle_collision(bone, path, positionFrame, handCollisionFrame) |
| 133 | return | 150 | return |
| 134 | - | ||
| 135 | bodyCollisionFrame = check_body_collision(isRightHand, last_keyframe, positionFrame) | 151 | bodyCollisionFrame = check_body_collision(isRightHand, last_keyframe, positionFrame) |
| 136 | if (bodyCollisionFrame != -1): | 152 | if (bodyCollisionFrame != -1): |
| 137 | handle_collision(bone, path, positionFrame, bodyCollisionFrame) | 153 | handle_collision(bone, path, positionFrame, bodyCollisionFrame) |
| @@ -153,13 +169,12 @@ def check_collision(objName, otherObjName, initFrame, endFrame): | @@ -153,13 +169,12 @@ def check_collision(objName, otherObjName, initFrame, endFrame): | ||
| 153 | startFrame = initFrame + int(math.fabs((endFrame - initFrame)/2)) | 169 | startFrame = initFrame + int(math.fabs((endFrame - initFrame)/2)) |
| 154 | collisionFrame = -1 | 170 | collisionFrame = -1 |
| 155 | for i in range(startFrame, endFrame + 1, 1): | 171 | for i in range(startFrame, endFrame + 1, 1): |
| 156 | - scene.frame_set(i) | ||
| 157 | - obj = scene.objects.get(objName) | ||
| 158 | - otherObj = scene.objects.get(otherObjName) | ||
| 159 | - | ||
| 160 | - if (bmesh_check_intersect_objects(obj, otherObj)): | ||
| 161 | - collisionFrame = i | ||
| 162 | - break | 172 | + scene.frame_set(i) |
| 173 | + obj = scene.objects.get(objName) | ||
| 174 | + otherObj = scene.objects.get(otherObjName) | ||
| 175 | + if (bmesh_check_intersect_objects(obj, otherObj)): | ||
| 176 | + collisionFrame = i | ||
| 177 | + break | ||
| 163 | scene.frame_set(frame_current) | 178 | scene.frame_set(frame_current) |
| 164 | return collisionFrame | 179 | return collisionFrame |
| 165 | 180 | ||
| @@ -169,15 +184,8 @@ def check_body_collision(isRightHand, initFrame, endFrame): | @@ -169,15 +184,8 @@ def check_body_collision(isRightHand, initFrame, endFrame): | ||
| 169 | result = check_collision(hand_box, body_box, initFrame, endFrame) | 184 | result = check_collision(hand_box, body_box, initFrame, endFrame) |
| 170 | return result | 185 | return result |
| 171 | 186 | ||
| 172 | -# Função que limpa todos os keyframes e define a quantidade de frames | ||
| 173 | -def limpar_keyframes(): | ||
| 174 | - bpy.context.active_object.animation_data_clear() | ||
| 175 | - for i in bpy.data.objects: | ||
| 176 | - i.animation_data_clear() | ||
| 177 | - | ||
| 178 | # Função que define as configurações de saida | 187 | # Função que define as configurações de saida |
| 179 | def configure_output(): | 188 | def configure_output(): |
| 180 | - limpar_keyframes() | ||
| 181 | bpy.context.scene.frame_start = 0 | 189 | bpy.context.scene.frame_start = 0 |
| 182 | bpy.context.scene.frame_current = bpy.context.scene.frame_start | 190 | bpy.context.scene.frame_current = bpy.context.scene.frame_start |
| 183 | bpy.context.scene.frame_end = bpy.context.scene.frame_start | 191 | bpy.context.scene.frame_end = bpy.context.scene.frame_start |
| @@ -195,6 +203,7 @@ def configure_output(): | @@ -195,6 +203,7 @@ def configure_output(): | ||
| 195 | bpy.context.scene.render.use_shadows = False | 203 | bpy.context.scene.render.use_shadows = False |
| 196 | bpy.context.scene.render.tile_x = 320 | 204 | bpy.context.scene.render.tile_x = 320 |
| 197 | bpy.context.scene.render.tile_y = 240 | 205 | bpy.context.scene.render.tile_y = 240 |
| 206 | + return | ||
| 198 | 207 | ||
| 199 | def render_sign(user_id, nome_sinal = "sinal", frame_final = bpy.context.scene.frame_end): | 208 | def render_sign(user_id, nome_sinal = "sinal", frame_final = bpy.context.scene.frame_end): |
| 200 | getcwd = os.path.dirname(os.path.abspath(__file__)) | 209 | getcwd = os.path.dirname(os.path.abspath(__file__)) |
| @@ -204,8 +213,9 @@ def render_sign(user_id, nome_sinal = "sinal", frame_final = bpy.context.scene.f | @@ -204,8 +213,9 @@ def render_sign(user_id, nome_sinal = "sinal", frame_final = bpy.context.scene.f | ||
| 204 | bpy.ops.render.render(animation = True, write_still = False, layer = "", scene = "") | 213 | bpy.ops.render.render(animation = True, write_still = False, layer = "", scene = "") |
| 205 | pyutil.file_rename("%s%0.4i-%0.4i.mp4" % (bpy.context.scene.render.filepath, bpy.context.scene.frame_start, bpy.context.scene.frame_end)) | 214 | pyutil.file_rename("%s%0.4i-%0.4i.mp4" % (bpy.context.scene.render.filepath, bpy.context.scene.frame_start, bpy.context.scene.frame_end)) |
| 206 | bpy.ops.wm.quit_blender() | 215 | bpy.ops.wm.quit_blender() |
| 216 | + return | ||
| 207 | 217 | ||
| 208 | -# descontinuada: get_endFrame | 218 | +""" |
| 209 | def get_endFrame(json_input, hands_frames_retilineo): | 219 | def get_endFrame(json_input, hands_frames_retilineo): |
| 210 | endsFrame = [18] | 220 | endsFrame = [18] |
| 211 | if(json_input["rightHand"] != []): | 221 | if(json_input["rightHand"] != []): |
| @@ -224,27 +234,24 @@ def get_endFrame(json_input, hands_frames_retilineo): | @@ -224,27 +234,24 @@ def get_endFrame(json_input, hands_frames_retilineo): | ||
| 224 | elif(json_input["rightHand"][0] == "retilineo"): | 234 | elif(json_input["rightHand"][0] == "retilineo"): |
| 225 | endsFrame.append(max(hands_frames_retilineo)) | 235 | endsFrame.append(max(hands_frames_retilineo)) |
| 226 | return(max(endsFrame)) | 236 | return(max(endsFrame)) |
| 237 | +""" | ||
| 227 | 238 | ||
| 228 | def validate_rotation(bone, endFrame, startFrame = 0): | 239 | def validate_rotation(bone, endFrame, startFrame = 0): |
| 229 | if (endFrame - startFrame == 1): | 240 | if (endFrame - startFrame == 1): |
| 230 | return True | 241 | return True |
| 231 | - | ||
| 232 | rotFrames = [[]] | 242 | rotFrames = [[]] |
| 233 | scene = bpy.context.scene | 243 | scene = bpy.context.scene |
| 234 | frame_current = scene.frame_current | 244 | frame_current = scene.frame_current |
| 235 | - | ||
| 236 | for i in range(startFrame+1, endFrame+1, 1): | 245 | for i in range(startFrame+1, endFrame+1, 1): |
| 237 | - scene.frame_set(i) | ||
| 238 | - rotFrames[-1] = bone.rotation_quaternion.to_euler() | ||
| 239 | - rotFrames.append([]) | ||
| 240 | - | 246 | + scene.frame_set(i) |
| 247 | + rotFrames[-1] = bone.rotation_quaternion.to_euler() | ||
| 248 | + rotFrames.append([]) | ||
| 241 | rotFrames.remove([]) | 249 | rotFrames.remove([]) |
| 242 | scene.frame_set(frame_current) | 250 | scene.frame_set(frame_current) |
| 243 | - | ||
| 244 | for k in range(1, len(rotFrames), 1): | 251 | for k in range(1, len(rotFrames), 1): |
| 245 | - for i in range(0, 3, 1): | ||
| 246 | - if (math.fabs(rotFrames[k][i] - rotFrames[k-1][i])) > math.pi/2: | ||
| 247 | - return False | 252 | + for i in range(0, 3, 1): |
| 253 | + if (math.fabs(rotFrames[k][i] - rotFrames[k-1][i])) > math.pi/2: | ||
| 254 | + return False | ||
| 248 | return True | 255 | return True |
| 249 | 256 | ||
| 250 | # Axis: "X", "Y" e "Z" | 257 | # Axis: "X", "Y" e "Z" |
| @@ -252,6 +259,5 @@ def apply_rotation(bone, axis, currentFrame, endFrame, degree): | @@ -252,6 +259,5 @@ def apply_rotation(bone, axis, currentFrame, endFrame, degree): | ||
| 252 | new_rotation = bone.rotation_quaternion.to_euler() | 259 | new_rotation = bone.rotation_quaternion.to_euler() |
| 253 | new_rotation.rotate_axis(axis, math.radians(degree)) | 260 | new_rotation.rotate_axis(axis, math.radians(degree)) |
| 254 | new_rotation = new_rotation.to_quaternion() | 261 | new_rotation = new_rotation.to_quaternion() |
| 255 | - | ||
| 256 | bone.rotation_quaternion = new_rotation | 262 | bone.rotation_quaternion = new_rotation |
| 257 | - keyframe_insert(bone, 'rotation_quaternion', currentFrame, False, True) | ||
| 258 | \ No newline at end of file | 263 | \ No newline at end of file |
| 264 | + keyframe_insert(bone, 'rotation_quaternion', currentFrame, False, True) |