-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlivelink.py
152 lines (127 loc) · 5.19 KB
/
livelink.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import bpy
from threading import Thread
from llv.buchse import Buchse
from llv.gesicht import FaceFrame
from .mapping import Functions, MirroredFunctions
from .recording import recorder
from .utils import props
props.add('mirrorUpdate', "Mirror Update", False)
props.add('faceLiveUpdatePose', "Live Update", False)
class FaceToggleUpdateButtonOperator(bpy.types.Operator):
bl_idname = "scene.face_toggle_update"
bl_label = "Toggle Live Update"
def execute(self, context):
if not bpy.context.scene.faceLiveUpdatePose:
bpy.context.scene.faceGlobalTimerStarted = True
bpy.context.scene.faceLiveUpdatePose = True
bpy.ops.wm.face_global_timer()
bpy.ops.wm.face_live_update_pose()
else:
bpy.context.scene.faceGlobalTimerStarted = False
bpy.context.scene.faceLiveUpdatePose = False
return {'FINISHED'}
class FaceSetNeutralButtonOperator(bpy.types.Operator):
bl_idname = "scene.face_set_neutral_pose"
bl_label = "Set Neutral Pose"
def execute(self, context):
recorder.set_neutral_pose()
return {'FINISHED'}
class FaceResetNeutralButtonOperator(bpy.types.Operator):
bl_idname = "scene.face_reset_neutral_pose"
bl_label = "Reset Neutral Pose"
def execute(self, context):
recorder.reset_neutral_pose()
return {'FINISHED'}
class FaceStartPortButtonOperator(bpy.types.Operator):
bl_idname = "scene.face_start_port"
bl_label = "Start Listen to Phone"
listening = False
last_msg = None
def execute(self, context):
t1 = Thread(target=self.record, daemon=True)
t1.start()
return {'FINISHED'}
def record(self, host='0.0.0.0', port=11111):
try:
buchse = Buchse(host, port, as_server=True)
except Exception as e:
FaceStartPortButtonOperator.listening = False
raise e
FaceStartPortButtonOperator.listening = True
try:
while True:
data, size = buchse.horch(FaceFrame.PACKET_MAX_SIZE)
if not data or 0 == size:
continue
try:
frame = FaceFrame.from_raw(data, size)
except Exception:
print("Failed to parse frame")
recorder.last_pose = None
continue
recorder.add_frame(frame)
finally:
FaceStartPortButtonOperator.listening = False
class FaceBLUpdatePose(bpy.types.Operator):
"""Playback Control"""
bl_label = "Start Update"
bl_idname = 'wm.face_live_update_pose'
def modal(self, context, event):
if not context.scene.faceLiveUpdatePose:
return self.cancel(context)
if event.type == 'TIMER':
if recorder.last_pose is not None:
if context.scene.mirrorUpdate:
f = MirroredFunctions
else:
f = Functions
pose = recorder.get_neutralized_pose(recorder.last_pose)
for key in f.keys():
(name, index) = key.split(':')
index = int(index)
value = f[key](pose)
if key == 'head:1':
bpy.data.objects['deform'].pose.bones[name].rotation_euler.y = value
else:
if index == 0:
bpy.data.objects['deform'].pose.bones[name].location.x = value
if index == 1:
bpy.data.objects['deform'].pose.bones[name].location.y = value
if index == 2:
bpy.data.objects['deform'].pose.bones[name].location.z = value
return {'PASS_THROUGH'}
def execute(self, context):
wm = context.window_manager
wm.modal_handler_add(self)
if not context.scene.faceGlobalTimerStarted:
bpy.ops.wm.face_global_timer()
return {'RUNNING_MODAL'}
def cancel(self, context):
return {'CANCELLED'}
@classmethod
def poll(cls, context):
return True
class FaceLiveLinkPanel(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = 'Sophia'
bl_label = "Face Live Link"
bl_idname = "VIEW3D_PT_face_update_panel"
def draw(self, context):
layout = self.layout
row = layout.row()
row.operator(FaceStartPortButtonOperator.bl_idname)
row.enabled = not FaceStartPortButtonOperator.listening
row = layout.row()
if not context.scene.faceLiveUpdatePose:
row.operator(FaceToggleUpdateButtonOperator.bl_idname, text = "Start Live Update")
else:
row.operator(FaceToggleUpdateButtonOperator.bl_idname, text = "Stop Live Update")
row.enabled = FaceStartPortButtonOperator.listening
row = layout.row()
row.operator(FaceSetNeutralButtonOperator.bl_idname)
if recorder.neutral_pose is not None:
row.operator(FaceResetNeutralButtonOperator.bl_idname)
row = layout.row()
row.prop(bpy.context.scene, "mirrorUpdate")
row.enabled = FaceStartPortButtonOperator.listening