Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit 9ea866c

Browse files
committed
fix eyes, break out interpolation data and extend it for models
Former-commit-id: d66253a
1 parent fe9b912 commit 9ea866c

File tree

10 files changed

+157
-183
lines changed

10 files changed

+157
-183
lines changed

entities/BasicModel.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func _ready() -> void:
4545
# Public functions #
4646
###############################################################################
4747

48-
func custom_update(_open_see_data: OpenSeeGD.OpenSeeData) -> void:
48+
func custom_update(_open_see_data: OpenSeeGD.OpenSeeData, _interpolation_data: InterpolationData) -> void:
4949
push_error("Model custom update not implemented")
5050

5151
func get_mapped_bones() -> Dictionary:

entities/basic-models/Duck.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func _unhandled_input(_event: InputEvent) -> void:
4343
# Public functions #
4444
###############################################################################
4545

46-
func custom_update(open_see_data: OpenSeeGD.OpenSeeData) -> void:
46+
func custom_update(open_see_data: OpenSeeGD.OpenSeeData, _interpolation_data: InterpolationData) -> void:
4747
if not is_blinking:
4848
if(open_see_data.left_eye_open < blink_threshold and open_see_data.right_eye_open < blink_threshold):
4949
blink()

entities/vrm/VRMModel.gd

Lines changed: 26 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ var mapped_meshes: Dictionary
2222
var blink_threshold: float = 0.3
2323
var eco_mode_is_blinking: bool = false
2424

25+
# Gaze
26+
var gaze_strength: float = 0.5
27+
2528
# Mouth
2629
var min_mouth_value: float = 0.0
2730

@@ -34,6 +37,7 @@ func _ready() -> void:
3437
rotation_damp = 0.01
3538
additional_bone_damp = 0.6
3639

40+
# TODO this is gross
3741
stored_offsets = get_parent().get_parent().stored_offsets
3842

3943
# Read vrm mappings
@@ -73,89 +77,46 @@ func _modify_blend_shape(mesh_instance: MeshInstance, blend_shape: String, value
7377
# Public functions #
7478
###############################################################################
7579

76-
func custom_update(data: OpenSeeGD.OpenSeeData) -> void:
80+
func set_expression(expression_name: String, expression_weight: float) -> void:
81+
for mesh_name in vrm_mappings[expression_name].get_meshes():
82+
for blend_name in vrm_mappings[expression_name].expression_data[mesh_name]:
83+
_modify_blend_shape(mapped_meshes[mesh_name], blend_name, expression_weight)
84+
85+
func custom_update(data: OpenSeeGD.OpenSeeData, interpolation_data: InterpolationData) -> void:
86+
# NOTE: Eye mappings are intentionally reversed so that the model mirrors the data
7787
# TODO i think this can be made more efficient
7888
if not eco_mode:
7989
# Left eye blinking
8090
if data.left_eye_open >= blink_threshold:
81-
for mesh_name in vrm_mappings.blink_l.get_meshes():
82-
for blend_name in vrm_mappings.blink_l.expression_data[mesh_name]:
83-
_modify_blend_shape(
84-
mapped_meshes[mesh_name],
85-
blend_name,
86-
1.0 - data.left_eye_open
87-
)
91+
set_expression("blink_r", 1.0 - data.left_eye_open)
8892
else:
89-
for mesh_name in vrm_mappings.blink_l.get_meshes():
90-
for blend_name in vrm_mappings.blink_l.expression_data[mesh_name]:
91-
_modify_blend_shape(
92-
mapped_meshes[mesh_name],
93-
blend_name,
94-
1.0
95-
)
93+
set_expression("blink_r", 1.0)
9694

9795
# Right eye blinking
9896
if data.right_eye_open >= blink_threshold:
99-
for mesh_name in vrm_mappings.blink_r.get_meshes():
100-
for blend_name in vrm_mappings.blink_r.expression_data[mesh_name]:
101-
_modify_blend_shape(
102-
mapped_meshes[mesh_name],
103-
blend_name,
104-
1.0 - data.right_eye_open
105-
)
97+
set_expression("blink_l", 1.0 - data.left_eye_open)
10698
else:
107-
for mesh_name in vrm_mappings.blink_r.get_meshes():
108-
for blend_name in vrm_mappings.blink_r.expression_data[mesh_name]:
109-
_modify_blend_shape(
110-
mapped_meshes[mesh_name],
111-
blend_name,
112-
1.0
113-
)
99+
set_expression("blink_l", 1.0)
114100

115101
# TODO eyes are a bit wonky
116-
# TODO left eye is biased towards corners
117-
# TODO right eye doesn't really look up or down
118-
# NOTE: We don't want the y-rotation when tracking gaze otherwise your eye will rotate in its socket
119102
# Left eye gaze
120103
var left_eye_transform: Transform = Transform()
121-
var left_eye_rotation: Vector3 = (stored_offsets.left_eye_gaze_offset - data.left_gaze.get_euler()) * 4
122-
left_eye_transform = left_eye_transform.rotated(Vector3.UP, left_eye_rotation.x)
123-
# if left_eye_rotation.z > 0:
124-
# left_eye_transform = left_eye_transform.rotated(Vector3.LEFT, -left_eye_rotation.z)
125-
# else:
126-
# left_eye_transform = left_eye_transform.rotated(Vector3.LEFT, left_eye_rotation.z)
127-
skeleton.set_bone_pose(left_eye_id, left_eye_transform)
104+
var left_eye_rotation: Vector3 = interpolation_data.interpolate(InterpolationData.InterpolationDataType.LEFT_EYE_ROTATION, gaze_strength)
105+
left_eye_transform = left_eye_transform.rotated(Vector3.RIGHT, -left_eye_rotation.x)
106+
left_eye_transform = left_eye_transform.rotated(Vector3.UP, left_eye_rotation.y)
107+
if Input.is_key_pressed(KEY_0): AppManager.log_message(str(left_eye_rotation))
108+
skeleton.set_bone_pose(right_eye_id, left_eye_transform)
128109

129110
# Right eye gaze
130111
var right_eye_transform: Transform = Transform()
131-
var right_eye_rotation: Vector3 = (stored_offsets.right_eye_gaze_offset - data.right_gaze.get_euler()) * 4
132-
right_eye_transform = right_eye_transform.rotated(Vector3.UP, right_eye_rotation.x)
133-
# if right_eye_rotation.z > 0:
134-
# right_eye_transform = right_eye_transform.rotated(Vector3.LEFT, right_eye_rotation.z)
135-
# else:
136-
# right_eye_transform = right_eye_transform.rotated(Vector3.LEFT, -right_eye_rotation.z)
137-
skeleton.set_bone_pose(right_eye_id, right_eye_transform)
138-
139-
# TODO im not sure what these are tracking?
140-
# Features eye left
141-
# var left_eye_transform: Transform = Transform()
142-
# print(data.features.eye_left)
143-
# left_eye_transform.rotated(Vector3.UP, data.features.eye_left * 1.5)
144-
# skeleton.set_bone_pose(left_eye_id, left_eye_transform)
145-
146-
# # Features eye right
147-
# var right_eye_transform: Transform = Transform()
148-
# right_eye_transform.rotated(Vector3.UP, data.features.eye_right * 1.5)
149-
# skeleton.set_bone_pose(right_eye_id, right_eye_transform)
112+
var right_eye_rotation: Vector3 = interpolation_data.interpolate(InterpolationData.InterpolationDataType.RIGHT_EYE_ROTATION, gaze_strength)
113+
right_eye_transform = right_eye_transform.rotated(Vector3.RIGHT, -right_eye_rotation.x)
114+
right_eye_transform = right_eye_transform.rotated(Vector3.UP, right_eye_rotation.y)
115+
if Input.is_key_pressed(KEY_1): AppManager.log_message(str(right_eye_rotation))
116+
skeleton.set_bone_pose(left_eye_id, right_eye_transform)
150117

151118
# Mouth tracking
152-
for mesh_name in vrm_mappings.a.get_meshes():
153-
for blend_name in vrm_mappings.a.expression_data[mesh_name]:
154-
_modify_blend_shape(
155-
mapped_meshes[mesh_name],
156-
blend_name,
157-
max(min_mouth_value, data.features.mouth_open)
158-
)
119+
set_expression("a", min(max(min_mouth_value, data.features.mouth_open * 2.0), 1.0))
159120
else:
160121
# TODO implement eco mode, should be more efficient than standard mode
161122
# Eco-mode blinking

project.godot

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ _global_script_classes=[ {
7575
"path": "res://screens/gui/elements/InputLabel.gd"
7676
}, {
7777
"base": "Reference",
78+
"class": "InterpolationData",
79+
"language": "GDScript",
80+
"path": "res://utils/InterpolationData.gd"
81+
}, {
82+
"base": "Reference",
7883
"class": "JSONUtil",
7984
"language": "GDScript",
8085
"path": "res://utils/JSONUtil.gd"
@@ -123,6 +128,7 @@ _global_script_class_icons={
123128
"IKCube": "",
124129
"ImportVRM": "",
125130
"InputLabel": "",
131+
"InterpolationData": "",
126132
"JSONUtil": "",
127133
"MainScreen": "",
128134
"ModelDisplayScreen": "",

screens/ModelDisplayScreen.gd

Lines changed: 34 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -59,32 +59,9 @@ var translation_adjustment: Vector3 = Vector3.ONE
5959
export var apply_rotation: bool = true
6060
var rotation_adjustment: Vector3 = Vector3.ONE
6161
export var interpolate_model: bool = true
62-
var interpolation_rate: float = 0.1
62+
var interpolation_rate: float = 0.1 setget _set_interpolation_rate
6363
var interpolation_data: InterpolationData = InterpolationData.new()
6464

65-
class InterpolationData:
66-
var last_updated: float
67-
var last_translation: Vector3
68-
var last_rotation: Vector3
69-
var target_translation: Vector3
70-
var target_rotation: Vector3
71-
72-
func _init() -> void:
73-
last_updated = 0.0
74-
last_translation = Vector3.ZERO
75-
last_rotation = Vector3.ZERO
76-
target_translation = Vector3.ZERO
77-
target_rotation = Vector3.ZERO
78-
79-
func update_values(
80-
p_last_updated: float,
81-
p_target_translation: Vector3,
82-
p_target_rotation: Vector3
83-
) -> void:
84-
last_updated = p_last_updated
85-
target_translation = p_target_translation
86-
target_rotation = p_target_rotation
87-
8865
export var tracking_start_delay: float = 2.0
8966

9067
###
@@ -194,82 +171,43 @@ func _ready() -> void:
194171
offset_timer.autostart = true
195172
self.call_deferred("add_child", offset_timer)
196173

197-
func _process(_delta: float) -> void:
174+
func _physics_process(_delta: float) -> void:
198175
if not stored_offsets:
199176
return
200-
if not interpolate_model:
201-
self.open_see_data = open_see.get_open_see_data(face_id)
202177

203-
if(not open_see_data or open_see_data.fit_3d_error > open_see.max_fit_3d_error):
204-
return
205-
206-
if open_see_data.time > updated:
207-
updated = open_see_data.time
208-
else:
209-
return
210-
211-
if apply_translation:
212-
head_translation = (stored_offsets.translation_offset - open_see_data.translation) * model.translation_damp
213-
214-
if apply_rotation:
215-
var corrected_euler: Vector3 = open_see_data.raw_euler
216-
if corrected_euler.x < 0.0:
217-
corrected_euler.x = 360 + corrected_euler.x
218-
head_rotation = (stored_offsets.euler_offset - corrected_euler) * model.rotation_damp
178+
self.open_see_data = open_see.get_open_see_data(face_id)
219179

220-
if model.has_custom_update:
221-
model.custom_update(open_see_data)
222-
223-
model.move_head(
224-
head_translation * translation_adjustment,
225-
head_rotation * rotation_adjustment
226-
)
227-
228-
func _physics_process(_delta: float) -> void:
229-
if not stored_offsets:
180+
if(not open_see_data or open_see_data.fit_3d_error > open_see.max_fit_3d_error):
230181
return
231-
if interpolate_model:
232-
self.open_see_data = open_see.get_open_see_data(face_id)
233-
234-
if(not open_see_data or open_see_data.fit_3d_error > open_see.max_fit_3d_error):
235-
return
236-
237-
# Don't return early if we are interpolating
238-
if open_see_data.time > updated:
239-
updated = open_see_data.time
240-
var corrected_euler: Vector3 = open_see_data.raw_euler
241-
if corrected_euler.x < 0.0:
242-
corrected_euler.x = 360 + corrected_euler.x
243-
interpolation_data.update_values(
244-
updated,
245-
(stored_offsets.translation_offset - open_see_data.translation),
246-
(stored_offsets.euler_offset - corrected_euler)
247-
)
248-
249-
if apply_translation:
250-
head_translation = lerp(
251-
interpolation_data.last_translation,
252-
interpolation_data.target_translation * model.translation_damp,
253-
interpolation_rate
254-
)
255-
interpolation_data.last_translation = head_translation
256-
257-
if apply_rotation:
258-
head_rotation = lerp(
259-
interpolation_data.last_rotation,
260-
interpolation_data.target_rotation * model.rotation_damp,
261-
interpolation_rate
262-
)
263-
interpolation_data.last_rotation = head_rotation
264-
265-
if model.has_custom_update:
266-
model.custom_update(open_see_data)
267182

268-
model.move_head(
269-
head_translation * translation_adjustment,
270-
head_rotation * rotation_adjustment
183+
# Don't return early if we are interpolating
184+
if open_see_data.time > updated:
185+
updated = open_see_data.time
186+
var corrected_euler: Vector3 = open_see_data.raw_euler
187+
if corrected_euler.x < 0.0:
188+
corrected_euler.x = 360 + corrected_euler.x
189+
interpolation_data.update_values(
190+
updated,
191+
stored_offsets.translation_offset - open_see_data.translation,
192+
stored_offsets.euler_offset - corrected_euler,
193+
stored_offsets.left_eye_gaze_offset - open_see_data.left_gaze.get_euler(),
194+
stored_offsets.right_eye_gaze_offset - open_see_data.right_gaze.get_euler()
271195
)
272196

197+
if apply_translation:
198+
head_translation = interpolation_data.interpolate(InterpolationData.InterpolationDataType.TRANSLATION, model.translation_damp)
199+
200+
if apply_rotation:
201+
head_rotation = interpolation_data.interpolate(InterpolationData.InterpolationDataType.ROTATION, model.rotation_damp)
202+
203+
if model.has_custom_update:
204+
model.custom_update(open_see_data, interpolation_data)
205+
206+
model.move_head(
207+
head_translation * translation_adjustment,
208+
head_rotation * rotation_adjustment
209+
)
210+
273211
func _unhandled_input(event: InputEvent) -> void:
274212
if event.is_action_pressed("ui_accept"):
275213
_save_offsets()
@@ -395,6 +333,10 @@ static func _find_bone_chain(skeleton: Skeleton, root_bone: int, tip_bone: int)
395333

396334
return result
397335

336+
func _set_interpolation_rate(value: float) -> void:
337+
interpolation_rate = value
338+
interpolation_data.rate = value
339+
398340
###############################################################################
399341
# Public functions #
400342
###############################################################################

screens/gui/ModelViewRight.gd

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ func _generate_properties(p_initial_properties: Dictionary = {}) -> void:
7474
data_source.interpolation_rate, TYPE_REAL)
7575

7676
func _apply_properties() -> void:
77+
# Interpolation data must be handled in a specific order since we don't check for interpolation anymore
78+
main_screen.model_display_screen.interpolate_model = v_box_container.get_node("interpolate_model").get_value()
79+
if not main_screen.model_display_screen.interpolate_model:
80+
main_screen.model_display_screen.interpolation_rate = 1.0
81+
else:
82+
main_screen.model_display_screen.interpolation_rate = v_box_container.get_node("interpolation_rate").get_value()
83+
7784
for c in v_box_container.get_children():
7885
# Null checks and value checks
7986
if c.get("line_edit"):
@@ -82,6 +89,7 @@ func _apply_properties() -> void:
8289
if c.line_edit_type == TYPE_REAL:
8390
if not c.line_edit.text.is_valid_float():
8491
continue
92+
8593
match c.name:
8694
"translation_damp":
8795
current_model.translation_damp = c.get_value()
@@ -93,10 +101,6 @@ func _apply_properties() -> void:
93101
main_screen.model_display_screen.apply_translation = c.get_value()
94102
"apply_rotation":
95103
main_screen.model_display_screen.apply_rotation = c.get_value()
96-
"interpolate_model":
97-
main_screen.model_display_screen.interpolate_model = c.get_value()
98-
"interpolation_rate":
99-
main_screen.model_display_screen.interpolation_rate = c.get_value()
100104

101105
func _setup() -> void:
102106
current_model = main_screen.model_display_screen.model

screens/gui/ModelViewRight.tscn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ script = ExtResource( 2 )
99
[node name="LoadModelButton" type="Button" parent="Control/MarginContainer/VBoxContainer" index="0"]
1010
margin_right = 1580.0
1111
margin_bottom = 79.0
12+
focus_mode = 0
1213
size_flags_vertical = 3
1314
size_flags_stretch_ratio = 0.1
1415
text = "Load Model"

0 commit comments

Comments
 (0)