Commit f89e6e67fea15bf070933c0675990dac8e38e593

Authored by Adabriand Furtado
1 parent cef27bb8
Exists in master

Adicionado o tratamento de colisão das mãos com bounding boxes

avatar_cartoon_v2.70.blend
No preview for this file type
avatar_cartoon_v2.74.blend 0 → 100755
No preview for this file type
bmesh_collision.py 0 → 100644
... ... @@ -0,0 +1,88 @@
  1 +import bpy
  2 +import bmesh
  3 +
  4 +def bmesh_copy_from_object(obj, transform=True, triangulate=True, apply_modifiers=False):
  5 +
  6 + assert(obj.type == 'MESH')
  7 +
  8 + if apply_modifiers and obj.modifiers:
  9 + me = obj.to_mesh(bpy.context.scene, True, 'PREVIEW', calc_tessface=False)
  10 + bm = bmesh.new()
  11 + bm.from_mesh(me)
  12 + bpy.data.meshes.remove(me)
  13 + else:
  14 + me = obj.data
  15 + if obj.mode == 'EDIT':
  16 + bm_orig = bmesh.from_edit_mesh(me)
  17 + bm = bm_orig.copy()
  18 + else:
  19 + bm = bmesh.new()
  20 + bm.from_mesh(me)
  21 +
  22 + # Remove custom data layers to save memory
  23 + for elem in (bm.faces, bm.edges, bm.verts, bm.loops):
  24 + for layers_name in dir(elem.layers):
  25 + if not layers_name.startswith("_"):
  26 + layers = getattr(elem.layers, layers_name)
  27 + for layer_name, layer in layers.items():
  28 + layers.remove(layer)
  29 +
  30 + if transform:
  31 + bm.transform(obj.matrix_world)
  32 +
  33 + if triangulate:
  34 + bmesh.ops.triangulate(bm, faces=bm.faces)
  35 +
  36 + return bm
  37 +
  38 +def bmesh_check_intersect_objects(obj, obj2):
  39 + assert(obj != obj2)
  40 +
  41 + # Triangulate
  42 + bm = bmesh_copy_from_object(obj, transform=True, triangulate=True)
  43 + bm2 = bmesh_copy_from_object(obj2, transform=True, triangulate=True)
  44 +
  45 + # If bm has more edges, use bm2 instead for looping over its edges
  46 + # (so we cast less rays from the simpler object to the more complex object)
  47 + if len(bm.edges) > len(bm2.edges):
  48 + bm2, bm = bm, bm2
  49 +
  50 + # Create a real mesh (lame!)
  51 + scene = bpy.context.scene
  52 + me_tmp = bpy.data.meshes.new(name="~temp~")
  53 + bm2.to_mesh(me_tmp)
  54 + bm2.free()
  55 + obj_tmp = bpy.data.objects.new(name=me_tmp.name, object_data=me_tmp)
  56 + scene.objects.link(obj_tmp)
  57 + scene.update()
  58 + ray_cast = obj_tmp.ray_cast
  59 +
  60 + intersect = False
  61 +
  62 + EPS_NORMAL = 0.000001
  63 + EPS_CENTER = 0.01 # should always be bigger
  64 +
  65 + #for ed in me_tmp.edges:
  66 + for ed in bm.edges:
  67 + v1, v2 = ed.verts
  68 +
  69 + # setup the edge with an offset
  70 + co_1 = v1.co.copy()
  71 + co_2 = v2.co.copy()
  72 + co_mid = (co_1 + co_2) * 0.5
  73 + no_mid = (v1.normal + v2.normal).normalized() * EPS_NORMAL
  74 + co_1 = co_1.lerp(co_mid, EPS_CENTER) + no_mid
  75 + co_2 = co_2.lerp(co_mid, EPS_CENTER) + no_mid
  76 +
  77 + co, no, index = ray_cast(co_1, co_2)
  78 + if index != -1:
  79 + intersect = True
  80 + break
  81 +
  82 + scene.objects.unlink(obj_tmp)
  83 + bpy.data.objects.remove(obj_tmp)
  84 + bpy.data.meshes.remove(me_tmp)
  85 +
  86 + scene.update()
  87 +
  88 + return intersect
0 89 \ No newline at end of file
... ...
libras.py
... ... @@ -36,7 +36,7 @@ def poseDefault(positionFrames, collisionFlag = False):
36 36 handDefaultParam = [0, 0, 0]
37 37 util.setPose(util.right_hand_actions, handDefaultParam, positionFrames, util.rightBonesConf, collisionFlag)
38 38 util.setPose(util.left_hand_actions, handDefaultParam, positionFrames, util.leftBonesConf, collisionFlag)
39   - # Setar a expressão facial padrão
  39 + #setFaceConfiguration([0], positionFrames, util.faceBonesConf)
40 40  
41 41 # Função responsável por setar as configurações das mãos
42 42 def setHandConfiguration(actions, handParam, positionFrames, bones):
... ... @@ -44,7 +44,7 @@ def setHandConfiguration(actions, handParam, positionFrames, bones):
44 44  
45 45 # Função responsável por setar a configuração da face
46 46 def setFaceConfiguration(handParam, positionFrames, bones):
47   - util.setPose(['007_Facial'], handParam, positionFrames, bones)
  47 + util.setPose(util.facial_expression_action, handParam, positionFrames, bones)
48 48  
49 49 # Sugestao: Alguma forma de uniformizar o calculo do endFrame (atualizado aqui e no movimento circular)
50 50 initialFrame, endFrame = 15, util.get_endFrame(json_input, util.hands_frames_retilineo)
... ... @@ -57,7 +57,7 @@ def configureHands():
57 57 hands = ["rightHand", "leftHand"]
58 58 iks = ["ik_FK.R", "ik_FK.L"]
59 59 bones_ = [util.rightBonesConf, util.leftBonesConf]
60   - #Array com as actions FAKES que seram selecionadas no Blender para cada lado do corpo
  60 + # Array com as actions FAKES que seram selecionadas no Blender para cada lado do corpo
61 61 actions = [util.right_hand_actions, util.left_hand_actions]
62 62 global endFrame
63 63 for i in range(len(hands)):
... ...
util.py
... ... @@ -2,8 +2,7 @@
2 2  
3 3 import bpy
4 4 import math
5   -#from bmesh_collision import bmesh_check_intersect_objects
6   -#from pyutil import log
  5 +from bmesh_collision import bmesh_check_intersect_objects
7 6  
8 7 armature = bpy.context.scene.objects.get('Armature.001')
9 8  
... ... @@ -20,7 +19,7 @@ faceBonesConf = [15, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47]
20 19 allBones = list(range(len(armature.pose.bones)))
21 20  
22 21 # define a posição dos keyframes
23   -hands_default_frames = [15, 18]
  22 +hands_default_frames = [15]
24 23  
25 24 # define a posição dos keyframes
26 25 hands_frames_retilineo = [30, 33]
... ... @@ -30,11 +29,21 @@ cocar_mao_aberta_index = 56
30 29 cocar_mao_fechada_index = 24
31 30 cocar_orientation_index = 20
32 31  
  32 +# Action expressão facial
  33 +facial_expression_id ='07_facial'
  34 +facial_expression_action = [facial_expression_id]
  35 +
33 36 # Actions mão direita
34   -right_hand_actions = [0, 2, 4]
  37 +conf_direita_id = '01_conf_direita'
  38 +pa_direita_id = '03_pa_direita'
  39 +orient_direita_id = '05_orient_direita'
  40 +right_hand_actions = [conf_direita_id, pa_direita_id, orient_direita_id]
35 41  
36 42 # Actions mão esquerda
37   -left_hand_actions = [1, 3, 5]
  43 +conf_esquerda_id = '02_conf_esquerda'
  44 +pa_esquerda_id = '04_pa_esquerda'
  45 +orient_esquerda_id = '06_orient_esquerda'
  46 +left_hand_actions = [conf_esquerda_id, pa_esquerda_id, orient_esquerda_id]
38 47  
39 48 last_keyframe_dict = {}
40 49  
... ... @@ -46,14 +55,84 @@ def setPose(actions, parametesConf, positionFrames, bones, collisionFlag = True)
46 55  
47 56 for x in range(len(positionFrames)):
48 57 for l in range(len(actions)):
49   - armature.pose_library = bpy.data.actions[actions[l]]
  58 + action = actions[l]
  59 + armature.pose_library = bpy.data.actions[action]
50 60 bpy.ops.poselib.apply_pose(pose_index = parametesConf[l])
51 61 for i in range(0, (len(bones))):
52   - keyframe_insert(armature.pose.bones[bones[i]], 'location', positionFrames[x], collisionFlag)
53   - keyframe_insert(armature.pose.bones[bones[i]], 'rotation_quaternion', positionFrames[x], collisionFlag)
54   -
55   -def keyframe_insert(bone, path, positionFrame, collisionFlag = True):
  62 + bone = armature.pose.bones[bones[i]]
  63 + validHandConf = action in [conf_direita_id, conf_esquerda_id] and "BnDedo" in bone.name
  64 + validPA = action in [pa_direita_id, pa_esquerda_id] and "ik_FK" in bone.name or "BnPolyV" in bone.name
  65 + validO = action in [orient_direita_id, orient_esquerda_id] and "BnMao" in bone.name
  66 +
  67 + if (validHandConf or validPA or validO):
  68 + keyframe_insert(bone, 'location', positionFrames[x], collisionFlag and validPA, validO)
  69 + keyframe_insert(bone, 'rotation_quaternion', positionFrames[x], collisionFlag and validPA, validO)
  70 +
  71 +def keyframe_insert(bone, path, positionFrame, collisionFlag = True, rotationFlag = False):
56 72 bone.keyframe_insert(data_path = path, index = -1, frame = positionFrame)
  73 + keyframe_id = bone.name + "_" + path
  74 + last_keyframe = last_keyframe_dict[keyframe_id] if keyframe_id in last_keyframe_dict else 0
  75 + last_keyframe_dict[keyframe_id] = positionFrame
  76 +
  77 + if (rotationFlag and path == "rotation_quaternion"):
  78 + checkRotation(bone, positionFrame, last_keyframe)
  79 +
  80 + if (collisionFlag):
  81 + checkCollision(bone, path, positionFrame, last_keyframe)
  82 +
  83 +def resetIKPosition(isRightHand):
  84 + armature.pose_library = bpy.data.actions[pa_direita_id if isRightHand else pa_esquerda_id]
  85 + bpy.ops.poselib.apply_pose(pose_index = 0)
  86 +
  87 +def resetBnMaoPosition(isRightHand):
  88 + armature.pose_library = bpy.data.actions[orient_direita_id if isRightHand else orient_esquerda_id]
  89 + bpy.ops.poselib.apply_pose(pose_index = 0)
  90 +
  91 +def checkRotation(bone, positionFrame, last_keyframe):
  92 + scene = bpy.context.scene
  93 + frame_current = bpy.context.scene.frame_current
  94 + scene.frame_set(positionFrame)
  95 + boneRQ = bone.rotation_quaternion.to_euler()
  96 + scene.frame_set(frame_current)
  97 + isRightHand = ".R" in bone.name
  98 + resetBnMaoPosition(isRightHand)
  99 + valid_rotation = validate_rotation(bone, positionFrame, last_keyframe)
  100 +
  101 + if (not valid_rotation):
  102 + new_rotation = boneRQ.to_quaternion() * (-1)
  103 + bone.rotation_quaternion = new_rotation
  104 + bone.keyframe_insert(data_path = 'rotation_quaternion', index = -1, frame = positionFrame)
  105 +
  106 +def checkCollision(bone, path, positionFrame, last_keyframe):
  107 + isRightHand = ".R" in bone.name
  108 + resetIKPosition(isRightHand)
  109 + collisionFrame = check_collision(last_keyframe, positionFrame)
  110 +
  111 + if (last_keyframe != positionFrame and collisionFrame != -1):
  112 + handle_collision(bone, path, positionFrame, collisionFrame)
  113 +
  114 +def handle_collision(bone, path, positionFrame, collisionFrame, rollbackFrames = 0):
  115 + scene = bpy.context.scene
  116 + frame_current = bpy.context.scene.frame_current
  117 + scene.frame_set(collisionFrame - rollbackFrames)
  118 + bone.keyframe_insert(data_path = path, index = -1, frame = positionFrame)
  119 + bpy.context.scene.frame_set(frame_current)
  120 +
  121 +def check_collision(initFrame, endFrame):
  122 + scene = bpy.context.scene
  123 + frame_current = bpy.context.scene.frame_current
  124 + startFrame = initFrame + int(math.fabs((endFrame - initFrame)/2))
  125 + collisionFrame = -1
  126 + for i in range(startFrame, endFrame + 1, 1):
  127 + scene.frame_set(i)
  128 + right_cube = bpy.context.scene.objects.get('right_hand_box')
  129 + left_cube = bpy.context.scene.objects.get('left_hand_box')
  130 +
  131 + if (bmesh_check_intersect_objects(right_cube, left_cube)):
  132 + collisionFrame = i
  133 + break
  134 + scene.frame_set(frame_current)
  135 + return collisionFrame
57 136  
58 137 # Função que limpa todos os keyframes e define a quantidade de frames
59 138 def erase_all_keyframes():
... ... @@ -117,12 +196,15 @@ def get_endFrame(json_input, hands_frames_retilineo):
117 196 endsFrame.append(max(hands_frames_retilineo))
118 197 return(max(endsFrame))
119 198  
120   -def validate_rotation(bone, endFrame):
  199 +def validate_rotation(bone, endFrame, startFrame = 0):
  200 + if (endFrame - startFrame == 1):
  201 + return True
  202 +
121 203 rotFrames = [[]]
122 204 scene = bpy.context.scene
123 205 frame_current = bpy.context.scene.frame_current
124 206  
125   - for i in range(0, endFrame + 1,1):
  207 + for i in range(startFrame+1, endFrame+1, 1):
126 208 scene.frame_set(i)
127 209 rotFrames[-1] = bone.rotation_quaternion.to_euler()
128 210 rotFrames.append( [] )
... ... @@ -130,9 +212,9 @@ def validate_rotation(bone, endFrame):
130 212 rotFrames.remove([])
131 213 scene.frame_set(frame_current)
132 214  
133   - for k in range(1, endFrame + 1, 1):
  215 + for k in range(1, len(rotFrames), 1):
134 216 for i in range(0, 3, 1):
135   - if (math.fabs(rotFrames[k][i] - rotFrames[k-1][i])) > math.pi :
  217 + if (math.fabs(rotFrames[k][i] - rotFrames[k-1][i])) > math.pi/2:
136 218 return False
137 219 return True
138 220  
... ...