feat:add blink and breath cycle
This commit is contained in:
1 parent
d9bb9d5a62
commit
90c2749bce
4 files changed
+61
-5
No files matched your search
+21
-1
@@ -51,7 +51,9 @@ default_arg = {
|
||||
'preset': 'Low',
|
||||
'mouse_audio_input': False,
|
||||
'audio_sensitivity': '0.02',
|
||||
'audio_threshold': '10.0'
|
||||
'audio_threshold': '10.0',
|
||||
'blink_interval': '5.0',
|
||||
'breath_cycle': 'inf'
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -308,11 +310,18 @@ class LauncherPanel(wx.Panel):
|
||||
addOption('mouse_audio_input', title='Audio Input', desc='启用WASAPI音频输入控制嘴部动作', type=1)
|
||||
addOption('audio_sensitivity', title='Audio Sensitivity', desc='音频灵敏度,控制音频对嘴部动作的影响程度', type=2)
|
||||
addOption('audio_threshold', title='Audio Threshold', desc='音频阈值,低于此值的音频将被忽略', type=2)
|
||||
addOption('blink_interval', title='Blink Interval', desc='设置眨眼间隔时间',
|
||||
choices=['No Blink', '3 seconds', '5 seconds', '7 seconds'],
|
||||
mapping=['inf', '3.0', '5.0', '7.0'])
|
||||
addOption('min_cutoff', title='Min CutOff', desc='输入滤波频率截断,\n越小越平滑,越大静止时越灵敏',
|
||||
type=3, mapper=min_cutoff_mapper)
|
||||
addOption('beta', title='Beta', desc='输入滤波速度补偿,\n越小越平滑,越大运动时越灵敏',
|
||||
type=3, mapper=beta_mapper)
|
||||
|
||||
addOption('breath_cycle', title='Breath Cycle', desc='设置呼吸循环时间',
|
||||
choices=['No Breath', '3 seconds', '5 seconds', '7 seconds'],
|
||||
mapping=['inf', '3.0', '5.0', '7.0'])
|
||||
|
||||
addOption('output', title='Output', desc='选择输出目标',
|
||||
choices=['Spout2', 'OBS VirtualCam', 'Debug Output'],
|
||||
mapping=[0, 1, 2])
|
||||
@@ -390,8 +399,10 @@ class LauncherPanel(wx.Panel):
|
||||
self.optionSizer.Hide(self.optionDict['mouse_audio_input'])
|
||||
self.optionSizer.Hide(self.optionDict['audio_sensitivity'])
|
||||
self.optionSizer.Hide(self.optionDict['audio_threshold'])
|
||||
self.optionSizer.Hide(self.optionDict['blink_interval'])
|
||||
else:
|
||||
self.optionSizer.Show(self.optionDict['mouse_audio_input'])
|
||||
self.optionSizer.Show(self.optionDict['blink_interval'])
|
||||
# Update audio fields based on checkbox state
|
||||
audioInputChoice()
|
||||
|
||||
@@ -533,11 +544,20 @@ class LauncherPanel(wx.Panel):
|
||||
if args['audio_threshold']:
|
||||
run_args.append('--audio_threshold')
|
||||
run_args.append(str(args['audio_threshold']))
|
||||
# Add blink interval for mouse input
|
||||
if args['blink_interval']:
|
||||
run_args.append('--blink_interval')
|
||||
run_args.append(str(args['blink_interval']))
|
||||
elif args['input'] == 4:
|
||||
if len(args['osf']):
|
||||
run_args.append('--osf_input')
|
||||
run_args.append(args['osf'])
|
||||
|
||||
# Add breath cycle option
|
||||
if args['breath_cycle']:
|
||||
run_args.append('--breath_cycle')
|
||||
run_args.append(str(args['breath_cycle']))
|
||||
|
||||
if args['output'] == 0:
|
||||
run_args.append('--output_spout2')
|
||||
elif args['output'] == 1:
|
||||
|
||||
@@ -24,6 +24,8 @@ parser.add_argument('--osf_input', type=str)
|
||||
parser.add_argument('--mouse_audio_input', action='store_true')
|
||||
parser.add_argument('--audio_sensitivity', type=float, default=0.02)
|
||||
parser.add_argument('--audio_threshold', type=float, default=10.0)
|
||||
parser.add_argument('--blink_interval', type=float, default=5.0)
|
||||
parser.add_argument('--breath_cycle', type=float, default=float('inf'))
|
||||
|
||||
parser.add_argument('--output_virtual_cam', action='store_true')
|
||||
parser.add_argument('--output_spout2', action='store_true')
|
||||
|
||||
@@ -67,8 +67,8 @@ class FaceMeshClientProcess(Process):
|
||||
mouth_eye_vector = [0.0] * 27
|
||||
pose_vector = [0.0] * 6
|
||||
|
||||
mouth_eye_vector[2] = min(eye_l_h_temp, eye_r_h_temp)
|
||||
mouth_eye_vector[3] = min(eye_l_h_temp, eye_r_h_temp)
|
||||
mouth_eye_vector[2] = max(eye_l_h_temp, eye_r_h_temp)
|
||||
mouth_eye_vector[3] = max(eye_l_h_temp, eye_r_h_temp)
|
||||
|
||||
mouth_eye_vector[14] = mouth_ratio * 2.0
|
||||
|
||||
|
||||
+36
-2
@@ -79,6 +79,14 @@ class MouseClientProcess(Process):
|
||||
}
|
||||
last_time : float = time.perf_counter()
|
||||
interval : float = 1.0 / 60 # 60 FPS
|
||||
|
||||
# 眨眼相关参数
|
||||
blink_interval = args.blink_interval # 眨眼间隔时间(秒)
|
||||
blink_duration = 0.25 # 眨眼持续时间(秒)
|
||||
last_blink_time = time.perf_counter()
|
||||
|
||||
# 呼吸循环参数
|
||||
breath_start_time = time.perf_counter()
|
||||
|
||||
print("Mouse Input Running at 60 FPS")
|
||||
position_vector = np.array([0, 0, 0, 1], dtype=np.float32)
|
||||
@@ -89,11 +97,36 @@ class MouseClientProcess(Process):
|
||||
head_eye_reduce = 0.6
|
||||
head_slowness = 0.2
|
||||
|
||||
# 计算眨眼效果
|
||||
current_time = time.perf_counter()
|
||||
time_since_last_blink = current_time - last_blink_time
|
||||
|
||||
# 每隔 blink_interval 秒眨一次眼
|
||||
if time_since_last_blink >= blink_interval:
|
||||
last_blink_time = current_time
|
||||
time_since_last_blink = 0
|
||||
|
||||
# 计算眨眼动画(使用尖锐的 sin 函数)
|
||||
if time_since_last_blink < blink_duration:
|
||||
# 在眨眼持续时间内,使用 sin 函数从 0 升到接近 1 再返回 0
|
||||
# 使用 sin^2 使曲线更尖锐
|
||||
blink_progress = time_since_last_blink / blink_duration * np.pi
|
||||
blink_value = np.sin(blink_progress) ** 2
|
||||
eye_close = blink_value * 1.0 # 升到1,返回到 0
|
||||
else:
|
||||
eye_close = 0.0
|
||||
|
||||
# 计算呼吸效果(使用 sin 函数,在 breath_cycle 时间内从 0 到 1 再到 0)
|
||||
breath_elapsed = (current_time - breath_start_time) % args.breath_cycle
|
||||
# 使用 sin 函数,让值在一个周期内从 0 -> 1 -> 0
|
||||
# sin 在 0 到 π 之间从 0 到 1 到 0
|
||||
breath_value = np.sin(breath_elapsed / args.breath_cycle * np.pi)
|
||||
|
||||
# 获取音频音量并映射到 mouth_ratio
|
||||
current_mouth_ratio = audio_filter(self.audio_volume.value, time.perf_counter()) if self.audio_running else 0
|
||||
mouse_data = {
|
||||
'eye_l_h_temp': 0,
|
||||
'eye_r_h_temp': 0,
|
||||
'eye_l_h_temp': eye_close,
|
||||
'eye_r_h_temp': eye_close,
|
||||
'mouth_ratio': current_mouth_ratio,
|
||||
'eye_y_ratio': np.interp(pos[1], [posLimit[1], posLimit[3]], [1, -1]) * eye_limit[1],
|
||||
'eye_x_ratio': np.interp(pos[0], [posLimit[0], posLimit[2]], [1, -1]) * eye_limit[0],
|
||||
@@ -136,6 +169,7 @@ class MouseClientProcess(Process):
|
||||
pose_vector[2] = z_angle
|
||||
pose_vector[3] = pose_vector[1]
|
||||
pose_vector[4] = pose_vector[2]
|
||||
pose_vector[5] = breath_value
|
||||
|
||||
model_input_arr = eyebrow_vector
|
||||
model_input_arr.extend(mouth_eye_vector)
|
||||
|
||||
Reference in new issue
Block a user