Commit f89e6e67fea15bf070933c0675990dac8e38e593
1 parent
cef27bb8
Exists in
master
Adicionado o tratamento de colisão das mãos com bounding boxes
Showing
5 changed files
with
187 additions
and
17 deletions
Show diff stats
avatar_cartoon_v2.70.blend
No preview for this file type
No preview for this file type
@@ -0,0 +1,88 @@ | @@ -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 | \ No newline at end of file | 89 | \ No newline at end of file |
libras.py
@@ -36,7 +36,7 @@ def poseDefault(positionFrames, collisionFlag = False): | @@ -36,7 +36,7 @@ def poseDefault(positionFrames, collisionFlag = False): | ||
36 | handDefaultParam = [0, 0, 0] | 36 | handDefaultParam = [0, 0, 0] |
37 | util.setPose(util.right_hand_actions, handDefaultParam, positionFrames, util.rightBonesConf, collisionFlag) | 37 | util.setPose(util.right_hand_actions, handDefaultParam, positionFrames, util.rightBonesConf, collisionFlag) |
38 | util.setPose(util.left_hand_actions, handDefaultParam, positionFrames, util.leftBonesConf, collisionFlag) | 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 | # Função responsável por setar as configurações das mãos | 41 | # Função responsável por setar as configurações das mãos |
42 | def setHandConfiguration(actions, handParam, positionFrames, bones): | 42 | def setHandConfiguration(actions, handParam, positionFrames, bones): |
@@ -44,7 +44,7 @@ def setHandConfiguration(actions, handParam, positionFrames, bones): | @@ -44,7 +44,7 @@ def setHandConfiguration(actions, handParam, positionFrames, bones): | ||
44 | 44 | ||
45 | # Função responsável por setar a configuração da face | 45 | # Função responsável por setar a configuração da face |
46 | def setFaceConfiguration(handParam, positionFrames, bones): | 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 | # Sugestao: Alguma forma de uniformizar o calculo do endFrame (atualizado aqui e no movimento circular) | 49 | # Sugestao: Alguma forma de uniformizar o calculo do endFrame (atualizado aqui e no movimento circular) |
50 | initialFrame, endFrame = 15, util.get_endFrame(json_input, util.hands_frames_retilineo) | 50 | initialFrame, endFrame = 15, util.get_endFrame(json_input, util.hands_frames_retilineo) |
@@ -57,7 +57,7 @@ def configureHands(): | @@ -57,7 +57,7 @@ def configureHands(): | ||
57 | hands = ["rightHand", "leftHand"] | 57 | hands = ["rightHand", "leftHand"] |
58 | iks = ["ik_FK.R", "ik_FK.L"] | 58 | iks = ["ik_FK.R", "ik_FK.L"] |
59 | bones_ = [util.rightBonesConf, util.leftBonesConf] | 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 | actions = [util.right_hand_actions, util.left_hand_actions] | 61 | actions = [util.right_hand_actions, util.left_hand_actions] |
62 | global endFrame | 62 | global endFrame |
63 | for i in range(len(hands)): | 63 | for i in range(len(hands)): |
util.py
@@ -2,8 +2,7 @@ | @@ -2,8 +2,7 @@ | ||
2 | 2 | ||
3 | import bpy | 3 | import bpy |
4 | import math | 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 | armature = bpy.context.scene.objects.get('Armature.001') | 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,7 +19,7 @@ faceBonesConf = [15, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47] | ||
20 | allBones = list(range(len(armature.pose.bones))) | 19 | allBones = list(range(len(armature.pose.bones))) |
21 | 20 | ||
22 | # define a posição dos keyframes | 21 | # define a posição dos keyframes |
23 | -hands_default_frames = [15, 18] | 22 | +hands_default_frames = [15] |
24 | 23 | ||
25 | # define a posição dos keyframes | 24 | # define a posição dos keyframes |
26 | hands_frames_retilineo = [30, 33] | 25 | hands_frames_retilineo = [30, 33] |
@@ -30,11 +29,21 @@ cocar_mao_aberta_index = 56 | @@ -30,11 +29,21 @@ cocar_mao_aberta_index = 56 | ||
30 | cocar_mao_fechada_index = 24 | 29 | cocar_mao_fechada_index = 24 |
31 | cocar_orientation_index = 20 | 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 | # Actions mão direita | 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 | # Actions mão esquerda | 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 | last_keyframe_dict = {} | 48 | last_keyframe_dict = {} |
40 | 49 | ||
@@ -46,14 +55,84 @@ def setPose(actions, parametesConf, positionFrames, bones, collisionFlag = True) | @@ -46,14 +55,84 @@ def setPose(actions, parametesConf, positionFrames, bones, collisionFlag = True) | ||
46 | 55 | ||
47 | for x in range(len(positionFrames)): | 56 | for x in range(len(positionFrames)): |
48 | for l in range(len(actions)): | 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 | bpy.ops.poselib.apply_pose(pose_index = parametesConf[l]) | 60 | bpy.ops.poselib.apply_pose(pose_index = parametesConf[l]) |
51 | for i in range(0, (len(bones))): | 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 | bone.keyframe_insert(data_path = path, index = -1, frame = positionFrame) | 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 | # Função que limpa todos os keyframes e define a quantidade de frames | 137 | # Função que limpa todos os keyframes e define a quantidade de frames |
59 | def erase_all_keyframes(): | 138 | def erase_all_keyframes(): |
@@ -117,12 +196,15 @@ def get_endFrame(json_input, hands_frames_retilineo): | @@ -117,12 +196,15 @@ def get_endFrame(json_input, hands_frames_retilineo): | ||
117 | endsFrame.append(max(hands_frames_retilineo)) | 196 | endsFrame.append(max(hands_frames_retilineo)) |
118 | return(max(endsFrame)) | 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 | rotFrames = [[]] | 203 | rotFrames = [[]] |
122 | scene = bpy.context.scene | 204 | scene = bpy.context.scene |
123 | frame_current = bpy.context.scene.frame_current | 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 | scene.frame_set(i) | 208 | scene.frame_set(i) |
127 | rotFrames[-1] = bone.rotation_quaternion.to_euler() | 209 | rotFrames[-1] = bone.rotation_quaternion.to_euler() |
128 | rotFrames.append( [] ) | 210 | rotFrames.append( [] ) |
@@ -130,9 +212,9 @@ def validate_rotation(bone, endFrame): | @@ -130,9 +212,9 @@ def validate_rotation(bone, endFrame): | ||
130 | rotFrames.remove([]) | 212 | rotFrames.remove([]) |
131 | scene.frame_set(frame_current) | 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 | for i in range(0, 3, 1): | 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 | return False | 218 | return False |
137 | return True | 219 | return True |
138 | 220 |