Initial commit
This commit is contained in:
commit
74d66bddf5
19 changed files with 1453 additions and 0 deletions
140
src/common.rs
Normal file
140
src/common.rs
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
use godot::prelude::*;
|
||||
use crate::face_data_object::FaceDataObject;
|
||||
|
||||
#[derive(GodotConvert, Var, Export, Debug)]
|
||||
#[godot(via = GString)]
|
||||
pub enum ReadBlendShape {
|
||||
EyeBlinkLeft,
|
||||
EyeLookDownLeft,
|
||||
EyeLookInLeft,
|
||||
EyeLookOutLeft,
|
||||
EyeLookUpLeft,
|
||||
EyeSquintLeft,
|
||||
EyeWideLeft,
|
||||
EyeBlinkRight,
|
||||
EyeLookDownRight,
|
||||
EyeLookInRight,
|
||||
EyeLookOutRight,
|
||||
EyeLookUpRight,
|
||||
EyeSquintRight,
|
||||
EyeWideRight,
|
||||
JawForward,
|
||||
JawLeft,
|
||||
JawRight,
|
||||
JawOpen,
|
||||
MouthClose,
|
||||
MouthFunnel,
|
||||
MouthPucker,
|
||||
MouthLeft,
|
||||
MouthRight,
|
||||
MouthSmileLeft,
|
||||
MouthSmileRight,
|
||||
MouthFrownLeft,
|
||||
MouthFrownRight,
|
||||
MouthDimpleLeft,
|
||||
MouthDimpleRight,
|
||||
MouthStretchLeft,
|
||||
MouthStretchRight,
|
||||
MouthRollLower,
|
||||
MouthRollUpper,
|
||||
MouthShrugLower,
|
||||
MouthShrugUpper,
|
||||
MouthPressLeft,
|
||||
MouthPressRight,
|
||||
MouthLowerDownLeft,
|
||||
MouthLowerDownRight,
|
||||
MouthUpperUpLeft,
|
||||
MouthUpperUpRight,
|
||||
BrowDownLeft,
|
||||
BrowDownRight,
|
||||
BrowInnerUp,
|
||||
BrowOuterUpLeft,
|
||||
BrowOuterUpRight,
|
||||
CheekPuff,
|
||||
CheekSquintLeft,
|
||||
CheekSquintRight,
|
||||
NoseSneerLeft,
|
||||
NoseSneerRight,
|
||||
TongueOut,
|
||||
HeadYaw,
|
||||
HeadPitch,
|
||||
HeadRoll,
|
||||
LeftEyeYaw,
|
||||
LeftEyePitch,
|
||||
LeftEyeRoll,
|
||||
RightEyeYaw,
|
||||
RightEyePitch,
|
||||
RightEyeRoll,
|
||||
}
|
||||
|
||||
|
||||
pub fn map_range_clamped(val: f32, in_min: f32, in_max: f32, out_min: f32, out_max: f32) -> f32 {
|
||||
(val - in_min) / (in_max - in_min) * (out_max - out_min) + out_min
|
||||
}
|
||||
|
||||
pub fn map_blend_shape(value: &ReadBlendShape, face_data_object: Gd<FaceDataObject>) -> f32 {
|
||||
let fdo = face_data_object.bind();
|
||||
match value {
|
||||
ReadBlendShape::EyeBlinkLeft => fdo.get_eye_blink_left(),
|
||||
ReadBlendShape::EyeLookDownLeft => fdo.get_eye_look_down_left(),
|
||||
ReadBlendShape::EyeLookInLeft => fdo.get_eye_look_in_left(),
|
||||
ReadBlendShape::EyeLookOutLeft => fdo.get_eye_look_out_left(),
|
||||
ReadBlendShape::EyeLookUpLeft => fdo.get_eye_look_up_left(),
|
||||
ReadBlendShape::EyeSquintLeft => fdo.get_eye_squint_left(),
|
||||
ReadBlendShape::EyeWideLeft => fdo.get_eye_wide_left(),
|
||||
ReadBlendShape::EyeBlinkRight => fdo.get_eye_blink_right(),
|
||||
ReadBlendShape::EyeLookDownRight => fdo.get_eye_look_down_right(),
|
||||
ReadBlendShape::EyeLookInRight => fdo.get_eye_look_in_right(),
|
||||
ReadBlendShape::EyeLookOutRight => fdo.get_eye_look_out_right(),
|
||||
ReadBlendShape::EyeLookUpRight => fdo.get_eye_look_up_right(),
|
||||
ReadBlendShape::EyeSquintRight => fdo.get_eye_squint_right(),
|
||||
ReadBlendShape::EyeWideRight => fdo.get_eye_wide_right(),
|
||||
ReadBlendShape::JawForward => fdo.get_jaw_forward(),
|
||||
ReadBlendShape::JawLeft => fdo.get_jaw_left(),
|
||||
ReadBlendShape::JawRight => fdo.get_jaw_right(),
|
||||
ReadBlendShape::JawOpen => fdo.get_jaw_open(),
|
||||
ReadBlendShape::MouthClose => fdo.get_mouth_close(),
|
||||
ReadBlendShape::MouthFunnel => fdo.get_mouth_funnel(),
|
||||
ReadBlendShape::MouthPucker => fdo.get_mouth_pucker(),
|
||||
ReadBlendShape::MouthLeft => fdo.get_mouth_left(),
|
||||
ReadBlendShape::MouthRight => fdo.get_mouth_right(),
|
||||
ReadBlendShape::MouthSmileLeft => fdo.get_mouth_smile_left(),
|
||||
ReadBlendShape::MouthSmileRight => fdo.get_mouth_smile_right(),
|
||||
ReadBlendShape::MouthFrownLeft => fdo.get_mouth_frown_left(),
|
||||
ReadBlendShape::MouthFrownRight => fdo.get_mouth_frown_right(),
|
||||
ReadBlendShape::MouthDimpleLeft => fdo.get_mouth_dimple_left(),
|
||||
ReadBlendShape::MouthDimpleRight => fdo.get_mouth_dimple_right(),
|
||||
ReadBlendShape::MouthStretchLeft => fdo.get_mouth_stretch_left(),
|
||||
ReadBlendShape::MouthStretchRight => fdo.get_mouth_stretch_right(),
|
||||
ReadBlendShape::MouthRollLower => fdo.get_mouth_roll_lower(),
|
||||
ReadBlendShape::MouthRollUpper => fdo.get_mouth_roll_upper(),
|
||||
ReadBlendShape::MouthShrugLower => fdo.get_mouth_shrug_lower(),
|
||||
ReadBlendShape::MouthShrugUpper => fdo.get_mouth_shrug_upper(),
|
||||
ReadBlendShape::MouthPressLeft => fdo.get_mouth_press_left(),
|
||||
ReadBlendShape::MouthPressRight => fdo.get_mouth_press_right(),
|
||||
ReadBlendShape::MouthLowerDownLeft => fdo.get_mouth_lower_down_left(),
|
||||
ReadBlendShape::MouthLowerDownRight => fdo.get_mouth_lower_down_right(),
|
||||
ReadBlendShape::MouthUpperUpLeft => fdo.get_mouth_upper_up_left(),
|
||||
ReadBlendShape::MouthUpperUpRight => fdo.get_mouth_upper_up_right(),
|
||||
ReadBlendShape::BrowDownLeft => fdo.get_brow_down_left(),
|
||||
ReadBlendShape::BrowDownRight => fdo.get_brow_down_right(),
|
||||
ReadBlendShape::BrowInnerUp => fdo.get_brow_inner_up(),
|
||||
ReadBlendShape::BrowOuterUpLeft => fdo.get_brow_outer_up_left(),
|
||||
ReadBlendShape::BrowOuterUpRight => fdo.get_brow_outer_up_right(),
|
||||
ReadBlendShape::CheekPuff => fdo.get_cheek_puff(),
|
||||
ReadBlendShape::CheekSquintLeft => fdo.get_cheek_squint_left(),
|
||||
ReadBlendShape::CheekSquintRight => fdo.get_cheek_squint_right(),
|
||||
ReadBlendShape::NoseSneerLeft => fdo.get_nose_sneer_left(),
|
||||
ReadBlendShape::NoseSneerRight => fdo.get_nose_sneer_right(),
|
||||
ReadBlendShape::TongueOut => fdo.get_tongue_out(),
|
||||
ReadBlendShape::HeadYaw => fdo.get_head_yaw(),
|
||||
ReadBlendShape::HeadPitch => fdo.get_head_pitch(),
|
||||
ReadBlendShape::HeadRoll => fdo.get_head_roll(),
|
||||
ReadBlendShape::LeftEyeYaw => fdo.get_left_eye_yaw(),
|
||||
ReadBlendShape::LeftEyePitch => fdo.get_left_eye_pitch(),
|
||||
ReadBlendShape::LeftEyeRoll => fdo.get_left_eye_roll(),
|
||||
ReadBlendShape::RightEyeYaw => fdo.get_right_eye_yaw(),
|
||||
ReadBlendShape::RightEyePitch => fdo.get_right_eye_pitch(),
|
||||
ReadBlendShape::RightEyeRoll => fdo.get_right_eye_roll(),
|
||||
}
|
||||
}
|
||||
109
src/face_bone.rs
Normal file
109
src/face_bone.rs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
use std::borrow::BorrowMut;
|
||||
|
||||
use godot::{engine::Skeleton3D, prelude::*};
|
||||
|
||||
use crate::{
|
||||
common::{map_blend_shape, map_range_clamped, ReadBlendShape},
|
||||
face_data_object::FaceDataObject,
|
||||
face_transform_rotation::TransformAxis,
|
||||
live_link_server::LiveLinkServer,
|
||||
};
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=Node)]
|
||||
pub struct FaceBone {
|
||||
#[export]
|
||||
read_from: Option<Gd<LiveLinkServer>>,
|
||||
#[export]
|
||||
read_shape: ReadBlendShape,
|
||||
|
||||
#[export]
|
||||
target_skeleton: Option<Gd<Skeleton3D>>,
|
||||
#[export]
|
||||
target_bone: GString,
|
||||
|
||||
#[export]
|
||||
clamp_in_min: f32,
|
||||
#[export]
|
||||
clamp_in_max: f32,
|
||||
#[export]
|
||||
clamp_out_min: f32,
|
||||
#[export]
|
||||
clamp_out_max: f32,
|
||||
|
||||
#[export]
|
||||
transform_axis: TransformAxis,
|
||||
|
||||
pre_value: f32,
|
||||
|
||||
base: Base<Node>,
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl FaceBone {
|
||||
#[func]
|
||||
fn on_face_data(&mut self, changed: bool, face_data: Option<Gd<FaceDataObject>>) {
|
||||
if changed {
|
||||
let face_data = face_data.unwrap();
|
||||
let shape_val = map_blend_shape(&self.read_shape, face_data);
|
||||
self.pre_value = shape_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl INode for FaceBone {
|
||||
fn init(base: Base<Node>) -> Self {
|
||||
Self {
|
||||
read_from: None,
|
||||
read_shape: ReadBlendShape::EyeBlinkLeft,
|
||||
target_skeleton: None,
|
||||
target_bone: GString::default(),
|
||||
clamp_in_min: 0.0,
|
||||
clamp_in_max: 1.0,
|
||||
clamp_out_min: 0.0,
|
||||
clamp_out_max: 1.0,
|
||||
|
||||
transform_axis: TransformAxis::X,
|
||||
|
||||
pre_value: 0.0,
|
||||
|
||||
base,
|
||||
}
|
||||
}
|
||||
|
||||
fn ready(&mut self) {
|
||||
if let Some(mut server) = self.borrow_mut().read_from.take() {
|
||||
let callable = self.base_mut().callable("on_face_data");
|
||||
server.connect("face_data_updated".into(), callable);
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&mut self, _delta: f64) {
|
||||
let skeleton = self.get_target_skeleton();
|
||||
if let Some(mut target) = skeleton {
|
||||
let bone_id = target.find_bone(self.get_target_bone());
|
||||
let initial_rotation = target.get_bone_pose_rotation(bone_id);
|
||||
let mut rot_euler = initial_rotation.to_euler(EulerOrder::YXZ);
|
||||
let clamped = map_range_clamped(
|
||||
self.pre_value,
|
||||
self.clamp_in_min,
|
||||
self.clamp_in_max,
|
||||
self.clamp_out_min,
|
||||
self.clamp_out_max,
|
||||
);
|
||||
match self.transform_axis {
|
||||
TransformAxis::X => {
|
||||
rot_euler.x = clamped;
|
||||
}
|
||||
TransformAxis::Y => {
|
||||
rot_euler.y = clamped;
|
||||
}
|
||||
TransformAxis::Z => {
|
||||
rot_euler.z = clamped;
|
||||
}
|
||||
}
|
||||
target.set_bone_pose_rotation(bone_id, Quaternion::from_euler(rot_euler).normalized());
|
||||
}
|
||||
}
|
||||
}
|
||||
358
src/face_data_object.rs
Normal file
358
src/face_data_object.rs
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
use godot::prelude::*;
|
||||
use live_link_face::{FaceBlendShape, LiveLinkFace};
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=RefCounted)]
|
||||
pub struct FaceDataObject {
|
||||
#[var]
|
||||
eye_blink_left: f32,
|
||||
#[var]
|
||||
eye_look_down_left: f32,
|
||||
#[var]
|
||||
eye_look_in_left: f32,
|
||||
#[var]
|
||||
eye_look_out_left: f32,
|
||||
#[var]
|
||||
eye_look_up_left: f32,
|
||||
#[var]
|
||||
eye_squint_left: f32,
|
||||
#[var]
|
||||
eye_wide_left: f32,
|
||||
|
||||
#[var]
|
||||
eye_blink_right: f32,
|
||||
#[var]
|
||||
eye_look_down_right: f32,
|
||||
#[var]
|
||||
eye_look_in_right: f32,
|
||||
#[var]
|
||||
eye_look_out_right: f32,
|
||||
#[var]
|
||||
eye_look_up_right: f32,
|
||||
#[var]
|
||||
eye_squint_right: f32,
|
||||
#[var]
|
||||
eye_wide_right: f32,
|
||||
|
||||
#[var]
|
||||
jaw_forward: f32,
|
||||
#[var]
|
||||
jaw_left: f32,
|
||||
#[var]
|
||||
jaw_right: f32,
|
||||
#[var]
|
||||
jaw_open: f32,
|
||||
|
||||
#[var]
|
||||
mouth_close: f32,
|
||||
#[var]
|
||||
mouth_funnel: f32,
|
||||
#[var]
|
||||
mouth_pucker: f32,
|
||||
#[var]
|
||||
mouth_left: f32,
|
||||
#[var]
|
||||
mouth_right: f32,
|
||||
#[var]
|
||||
mouth_smile_left: f32,
|
||||
#[var]
|
||||
mouth_smile_right: f32,
|
||||
#[var]
|
||||
mouth_frown_left: f32,
|
||||
#[var]
|
||||
mouth_frown_right: f32,
|
||||
#[var]
|
||||
mouth_dimple_left: f32,
|
||||
#[var]
|
||||
mouth_dimple_right: f32,
|
||||
#[var]
|
||||
mouth_stretch_left: f32,
|
||||
#[var]
|
||||
mouth_stretch_right: f32,
|
||||
#[var]
|
||||
mouth_roll_lower: f32,
|
||||
#[var]
|
||||
mouth_roll_upper: f32,
|
||||
#[var]
|
||||
mouth_shrug_lower: f32,
|
||||
#[var]
|
||||
mouth_shrug_upper: f32,
|
||||
#[var]
|
||||
mouth_press_left: f32,
|
||||
#[var]
|
||||
mouth_press_right: f32,
|
||||
#[var]
|
||||
mouth_lower_down_left: f32,
|
||||
#[var]
|
||||
mouth_lower_down_right: f32,
|
||||
#[var]
|
||||
mouth_upper_up_left: f32,
|
||||
#[var]
|
||||
mouth_upper_up_right: f32,
|
||||
|
||||
#[var]
|
||||
brow_down_left: f32,
|
||||
#[var]
|
||||
brow_down_right: f32,
|
||||
#[var]
|
||||
brow_inner_up: f32,
|
||||
#[var]
|
||||
brow_outer_up_left: f32,
|
||||
#[var]
|
||||
brow_outer_up_right: f32,
|
||||
|
||||
#[var]
|
||||
cheek_puff: f32,
|
||||
#[var]
|
||||
cheek_squint_left: f32,
|
||||
#[var]
|
||||
cheek_squint_right: f32,
|
||||
|
||||
#[var]
|
||||
nose_sneer_left: f32,
|
||||
#[var]
|
||||
nose_sneer_right: f32,
|
||||
|
||||
#[var]
|
||||
tongue_out: f32,
|
||||
|
||||
#[var]
|
||||
head_yaw: f32,
|
||||
#[var]
|
||||
head_pitch: f32,
|
||||
#[var]
|
||||
head_roll: f32,
|
||||
|
||||
#[var]
|
||||
left_eye_yaw: f32,
|
||||
#[var]
|
||||
left_eye_pitch: f32,
|
||||
#[var]
|
||||
left_eye_roll: f32,
|
||||
|
||||
#[var]
|
||||
right_eye_yaw: f32,
|
||||
#[var]
|
||||
right_eye_pitch: f32,
|
||||
#[var]
|
||||
right_eye_roll: f32,
|
||||
|
||||
base: Base<RefCounted>,
|
||||
}
|
||||
|
||||
pub fn read_face_data(face_data_object: &mut Gd<FaceDataObject>, face_data: &LiveLinkFace) {
|
||||
let mut face_data_object = face_data_object.bind_mut();
|
||||
|
||||
face_data_object.eye_blink_left = face_data.get_blendshape(FaceBlendShape::EyeBlinkLeft);
|
||||
|
||||
face_data_object.eye_look_down_left = face_data.get_blendshape(FaceBlendShape::EyeLookDownLeft);
|
||||
|
||||
face_data_object.eye_look_in_left = face_data.get_blendshape(FaceBlendShape::EyeLookInLeft);
|
||||
|
||||
face_data_object.eye_look_out_left = face_data.get_blendshape(FaceBlendShape::EyeLookOutLeft);
|
||||
|
||||
face_data_object.eye_look_up_left = face_data.get_blendshape(FaceBlendShape::EyeLookUpLeft);
|
||||
|
||||
face_data_object.eye_squint_left = face_data.get_blendshape(FaceBlendShape::EyeSquintLeft);
|
||||
|
||||
face_data_object.eye_wide_left = face_data.get_blendshape(FaceBlendShape::EyeWideLeft);
|
||||
|
||||
face_data_object.eye_blink_right = face_data.get_blendshape(FaceBlendShape::EyeBlinkRight);
|
||||
|
||||
face_data_object.eye_look_down_right =
|
||||
face_data.get_blendshape(FaceBlendShape::EyeLookDownRight);
|
||||
|
||||
face_data_object.eye_look_in_right = face_data.get_blendshape(FaceBlendShape::EyeLookInRight);
|
||||
|
||||
face_data_object.eye_look_out_right = face_data.get_blendshape(FaceBlendShape::EyeLookOutRight);
|
||||
|
||||
face_data_object.eye_look_up_right = face_data.get_blendshape(FaceBlendShape::EyeLookUpRight);
|
||||
|
||||
face_data_object.eye_squint_right = face_data.get_blendshape(FaceBlendShape::EyeSquintRight);
|
||||
|
||||
face_data_object.eye_wide_right = face_data.get_blendshape(FaceBlendShape::EyeWideRight);
|
||||
|
||||
face_data_object.jaw_forward = face_data.get_blendshape(FaceBlendShape::JawForward);
|
||||
|
||||
face_data_object.jaw_left = face_data.get_blendshape(FaceBlendShape::JawLeft);
|
||||
|
||||
face_data_object.jaw_right = face_data.get_blendshape(FaceBlendShape::JawRight);
|
||||
|
||||
face_data_object.jaw_open = face_data.get_blendshape(FaceBlendShape::JawOpen);
|
||||
|
||||
face_data_object.mouth_close = face_data.get_blendshape(FaceBlendShape::MouthClose);
|
||||
|
||||
face_data_object.mouth_funnel = face_data.get_blendshape(FaceBlendShape::MouthFunnel);
|
||||
|
||||
face_data_object.mouth_pucker = face_data.get_blendshape(FaceBlendShape::MouthPucker);
|
||||
|
||||
face_data_object.mouth_left = face_data.get_blendshape(FaceBlendShape::MouthLeft);
|
||||
|
||||
face_data_object.mouth_right = face_data.get_blendshape(FaceBlendShape::MouthRight);
|
||||
|
||||
face_data_object.mouth_smile_left = face_data.get_blendshape(FaceBlendShape::MouthSmileLeft);
|
||||
|
||||
face_data_object.mouth_smile_right = face_data.get_blendshape(FaceBlendShape::MouthSmileRight);
|
||||
|
||||
face_data_object.mouth_frown_left = face_data.get_blendshape(FaceBlendShape::MouthFrownLeft);
|
||||
|
||||
face_data_object.mouth_frown_right = face_data.get_blendshape(FaceBlendShape::MouthFrownRight);
|
||||
|
||||
face_data_object.mouth_dimple_left = face_data.get_blendshape(FaceBlendShape::MouthDimpleLeft);
|
||||
|
||||
face_data_object.mouth_dimple_right =
|
||||
face_data.get_blendshape(FaceBlendShape::MouthDimpleRight);
|
||||
|
||||
face_data_object.mouth_stretch_left =
|
||||
face_data.get_blendshape(FaceBlendShape::MouthStretchLeft);
|
||||
|
||||
face_data_object.mouth_stretch_right =
|
||||
face_data.get_blendshape(FaceBlendShape::MouthStretchRight);
|
||||
|
||||
face_data_object.mouth_roll_lower = face_data.get_blendshape(FaceBlendShape::MouthRollLower);
|
||||
|
||||
face_data_object.mouth_roll_upper = face_data.get_blendshape(FaceBlendShape::MouthRollUpper);
|
||||
|
||||
face_data_object.mouth_shrug_lower = face_data.get_blendshape(FaceBlendShape::MouthShrugLower);
|
||||
|
||||
face_data_object.mouth_shrug_upper = face_data.get_blendshape(FaceBlendShape::MouthShrugUpper);
|
||||
|
||||
face_data_object.mouth_press_left = face_data.get_blendshape(FaceBlendShape::MouthPressLeft);
|
||||
|
||||
face_data_object.mouth_press_right = face_data.get_blendshape(FaceBlendShape::MouthPressRight);
|
||||
|
||||
face_data_object.mouth_lower_down_left =
|
||||
face_data.get_blendshape(FaceBlendShape::MouthLowerDownLeft);
|
||||
|
||||
face_data_object.mouth_lower_down_right =
|
||||
face_data.get_blendshape(FaceBlendShape::MouthLowerDownRight);
|
||||
|
||||
face_data_object.mouth_upper_up_left =
|
||||
face_data.get_blendshape(FaceBlendShape::MouthUpperUpLeft);
|
||||
|
||||
face_data_object.mouth_upper_up_right =
|
||||
face_data.get_blendshape(FaceBlendShape::MouthUpperUpRight);
|
||||
|
||||
face_data_object.brow_down_left = face_data.get_blendshape(FaceBlendShape::BrowDownLeft);
|
||||
|
||||
face_data_object.brow_down_right = face_data.get_blendshape(FaceBlendShape::BrowDownRight);
|
||||
|
||||
face_data_object.brow_inner_up = face_data.get_blendshape(FaceBlendShape::BrowInnerUp);
|
||||
|
||||
face_data_object.brow_outer_up_left = face_data.get_blendshape(FaceBlendShape::BrowOuterUpLeft);
|
||||
|
||||
face_data_object.brow_outer_up_right =
|
||||
face_data.get_blendshape(FaceBlendShape::BrowOuterUpRight);
|
||||
|
||||
face_data_object.cheek_puff = face_data.get_blendshape(FaceBlendShape::CheekPuff);
|
||||
|
||||
face_data_object.cheek_squint_left = face_data.get_blendshape(FaceBlendShape::CheekSquintLeft);
|
||||
|
||||
face_data_object.cheek_squint_right =
|
||||
face_data.get_blendshape(FaceBlendShape::CheekSquintRight);
|
||||
|
||||
face_data_object.nose_sneer_left = face_data.get_blendshape(FaceBlendShape::NoseSneerLeft);
|
||||
|
||||
face_data_object.nose_sneer_right = face_data.get_blendshape(FaceBlendShape::NoseSneerRight);
|
||||
|
||||
face_data_object.tongue_out = face_data.get_blendshape(FaceBlendShape::TongueOut);
|
||||
|
||||
face_data_object.head_yaw = face_data.get_blendshape(FaceBlendShape::HeadYaw);
|
||||
|
||||
face_data_object.head_pitch = face_data.get_blendshape(FaceBlendShape::HeadPitch);
|
||||
|
||||
face_data_object.head_roll = face_data.get_blendshape(FaceBlendShape::HeadRoll);
|
||||
|
||||
face_data_object.left_eye_yaw = face_data.get_blendshape(FaceBlendShape::LeftEyeYaw);
|
||||
|
||||
face_data_object.left_eye_pitch = face_data.get_blendshape(FaceBlendShape::LeftEyePitch);
|
||||
|
||||
face_data_object.left_eye_roll = face_data.get_blendshape(FaceBlendShape::LeftEyeRoll);
|
||||
|
||||
face_data_object.right_eye_yaw = face_data.get_blendshape(FaceBlendShape::RightEyeYaw);
|
||||
|
||||
face_data_object.right_eye_pitch = face_data.get_blendshape(FaceBlendShape::RightEyePitch);
|
||||
|
||||
face_data_object.right_eye_roll = face_data.get_blendshape(FaceBlendShape::RightEyeRoll);
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl IRefCounted for FaceDataObject {
|
||||
fn init(base: Base<RefCounted>) -> Self {
|
||||
Self {
|
||||
eye_blink_left: 0.0,
|
||||
eye_look_down_left: 0.0,
|
||||
eye_look_in_left: 0.0,
|
||||
eye_look_out_left: 0.0,
|
||||
eye_look_up_left: 0.0,
|
||||
eye_squint_left: 0.0,
|
||||
eye_wide_left: 0.0,
|
||||
|
||||
eye_blink_right: 0.0,
|
||||
eye_look_down_right: 0.0,
|
||||
eye_look_in_right: 0.0,
|
||||
eye_look_out_right: 0.0,
|
||||
eye_look_up_right: 0.0,
|
||||
eye_squint_right: 0.0,
|
||||
eye_wide_right: 0.0,
|
||||
|
||||
jaw_forward: 0.0,
|
||||
jaw_left: 0.0,
|
||||
jaw_right: 0.0,
|
||||
jaw_open: 0.0,
|
||||
|
||||
mouth_close: 0.0,
|
||||
mouth_funnel: 0.0,
|
||||
mouth_pucker: 0.0,
|
||||
mouth_left: 0.0,
|
||||
mouth_right: 0.0,
|
||||
mouth_smile_left: 0.0,
|
||||
mouth_smile_right: 0.0,
|
||||
mouth_frown_left: 0.0,
|
||||
mouth_frown_right: 0.0,
|
||||
mouth_dimple_left: 0.0,
|
||||
mouth_dimple_right: 0.0,
|
||||
mouth_stretch_left: 0.0,
|
||||
mouth_stretch_right: 0.0,
|
||||
mouth_roll_lower: 0.0,
|
||||
mouth_roll_upper: 0.0,
|
||||
mouth_shrug_lower: 0.0,
|
||||
mouth_shrug_upper: 0.0,
|
||||
mouth_press_left: 0.0,
|
||||
mouth_press_right: 0.0,
|
||||
mouth_lower_down_left: 0.0,
|
||||
mouth_lower_down_right: 0.0,
|
||||
mouth_upper_up_left: 0.0,
|
||||
mouth_upper_up_right: 0.0,
|
||||
|
||||
brow_down_left: 0.0,
|
||||
brow_down_right: 0.0,
|
||||
brow_inner_up: 0.0,
|
||||
brow_outer_up_left: 0.0,
|
||||
brow_outer_up_right: 0.0,
|
||||
|
||||
cheek_puff: 0.0,
|
||||
cheek_squint_left: 0.0,
|
||||
cheek_squint_right: 0.0,
|
||||
|
||||
nose_sneer_left: 0.0,
|
||||
nose_sneer_right: 0.0,
|
||||
|
||||
tongue_out: 0.0,
|
||||
|
||||
head_yaw: 0.0,
|
||||
head_pitch: 0.0,
|
||||
head_roll: 0.0,
|
||||
|
||||
left_eye_yaw: 0.0,
|
||||
left_eye_pitch: 0.0,
|
||||
left_eye_roll: 0.0,
|
||||
|
||||
right_eye_yaw: 0.0,
|
||||
right_eye_pitch: 0.0,
|
||||
right_eye_roll: 0.0,
|
||||
|
||||
base,
|
||||
}
|
||||
}
|
||||
}
|
||||
91
src/face_property.rs
Normal file
91
src/face_property.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
use std::borrow::BorrowMut;
|
||||
|
||||
use godot::prelude::*;
|
||||
|
||||
use crate::{
|
||||
common::{map_blend_shape, map_range_clamped, ReadBlendShape},
|
||||
face_data_object::FaceDataObject,
|
||||
live_link_server::LiveLinkServer,
|
||||
};
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=Node)]
|
||||
pub struct FaceProperty {
|
||||
#[export]
|
||||
read_from: Option<Gd<LiveLinkServer>>,
|
||||
#[export]
|
||||
read_shape: ReadBlendShape,
|
||||
|
||||
#[export]
|
||||
target_object: Option<Gd<Node>>,
|
||||
#[export]
|
||||
target_property: StringName,
|
||||
|
||||
#[export]
|
||||
clamp_in_min: f32,
|
||||
#[export]
|
||||
clamp_in_max: f32,
|
||||
#[export]
|
||||
clamp_out_min: f32,
|
||||
#[export]
|
||||
clamp_out_max: f32,
|
||||
|
||||
pre_value: f32,
|
||||
|
||||
base: Base<Node>,
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl FaceProperty {
|
||||
#[func]
|
||||
fn on_face_data(&mut self, changed: bool, face_data: Option<Gd<FaceDataObject>>) {
|
||||
if changed {
|
||||
let face_data = face_data.unwrap();
|
||||
let shape_val = map_blend_shape(&self.read_shape, face_data);
|
||||
self.pre_value = shape_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl INode for FaceProperty {
|
||||
fn init(base: Base<Node>) -> Self {
|
||||
Self {
|
||||
read_from: None,
|
||||
read_shape: ReadBlendShape::EyeBlinkLeft,
|
||||
target_object: None,
|
||||
target_property: StringName::default(),
|
||||
clamp_in_min: 0.0,
|
||||
clamp_in_max: 1.0,
|
||||
clamp_out_min: 0.0,
|
||||
clamp_out_max: 1.0,
|
||||
|
||||
pre_value: 0.0,
|
||||
|
||||
base,
|
||||
}
|
||||
}
|
||||
|
||||
fn ready(&mut self) {
|
||||
if let Some(mut server) = self.borrow_mut().read_from.take() {
|
||||
let callable = self.base_mut().callable("on_face_data");
|
||||
server.connect("face_data_updated".into(), callable);
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&mut self, _delta: f64) {
|
||||
let object = self.get_target_object();
|
||||
let property = self.get_target_property();
|
||||
|
||||
if let Some(mut target) = object {
|
||||
let value = map_range_clamped(
|
||||
self.pre_value,
|
||||
self.clamp_in_min,
|
||||
self.clamp_in_max,
|
||||
self.clamp_out_min,
|
||||
self.clamp_out_max,
|
||||
);
|
||||
target.set(property.clone(), Variant::from(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
112
src/face_transform_rotation.rs
Normal file
112
src/face_transform_rotation.rs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
use std::borrow::BorrowMut;
|
||||
|
||||
use godot::prelude::*;
|
||||
|
||||
use crate::{
|
||||
common::{map_blend_shape, map_range_clamped, ReadBlendShape},
|
||||
face_data_object::FaceDataObject,
|
||||
live_link_server::LiveLinkServer,
|
||||
};
|
||||
|
||||
#[derive(GodotConvert, Var, Export, Debug)]
|
||||
#[godot(via = GString)]
|
||||
pub enum TransformAxis {
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
}
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=Node)]
|
||||
pub struct FaceData {
|
||||
#[export]
|
||||
read_from: Option<Gd<LiveLinkServer>>,
|
||||
#[export]
|
||||
read_shape: ReadBlendShape,
|
||||
|
||||
#[export]
|
||||
target: Option<Gd<Node3D>>,
|
||||
|
||||
#[export]
|
||||
clamp_in_min: f32,
|
||||
#[export]
|
||||
clamp_in_max: f32,
|
||||
#[export]
|
||||
clamp_out_min: f32,
|
||||
#[export]
|
||||
clamp_out_max: f32,
|
||||
|
||||
#[export]
|
||||
transform_axis: TransformAxis,
|
||||
|
||||
pre_value: f32,
|
||||
|
||||
base: Base<Node>,
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl FaceData {
|
||||
#[func]
|
||||
fn on_face_data(&mut self, changed: bool, face_data: Option<Gd<FaceDataObject>>) {
|
||||
if changed {
|
||||
let face_data = face_data.unwrap();
|
||||
let shape_val = map_blend_shape(&self.read_shape, face_data);
|
||||
self.pre_value = shape_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl INode for FaceData {
|
||||
fn init(base: Base<Node>) -> Self {
|
||||
Self {
|
||||
read_from: None,
|
||||
read_shape: ReadBlendShape::EyeBlinkLeft,
|
||||
target: None,
|
||||
clamp_in_min: 0.0,
|
||||
clamp_in_max: 1.0,
|
||||
clamp_out_min: 0.0,
|
||||
clamp_out_max: 1.0,
|
||||
|
||||
transform_axis: TransformAxis::X,
|
||||
|
||||
pre_value: 0.0,
|
||||
|
||||
base,
|
||||
}
|
||||
}
|
||||
|
||||
fn ready(&mut self) {
|
||||
if let Some(mut server) = self.borrow_mut().read_from.take() {
|
||||
let callable = self.base_mut().callable("on_face_data");
|
||||
server.connect("face_data_updated".into(), callable);
|
||||
}
|
||||
}
|
||||
|
||||
fn process(&mut self, _delta: f64) {
|
||||
if let Some(target) = &mut self.target {
|
||||
let mut rotation = target.get_rotation_degrees();
|
||||
let clamped = map_range_clamped(
|
||||
self.pre_value,
|
||||
self.clamp_in_min,
|
||||
self.clamp_in_max,
|
||||
self.clamp_out_min,
|
||||
self.clamp_out_max,
|
||||
);
|
||||
|
||||
match self.transform_axis {
|
||||
TransformAxis::X => {
|
||||
rotation.x = clamped;
|
||||
}
|
||||
TransformAxis::Y => {
|
||||
rotation.y = clamped;
|
||||
}
|
||||
TransformAxis::Z => {
|
||||
rotation.z = clamped;
|
||||
}
|
||||
}
|
||||
|
||||
target.set_rotation_degrees(rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/lib.rs
Normal file
14
src/lib.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// use godot::engine::global::Error;
|
||||
use godot::prelude::*;
|
||||
|
||||
struct LiveLinkExtension;
|
||||
|
||||
#[gdextension]
|
||||
unsafe impl ExtensionLibrary for LiveLinkExtension {}
|
||||
|
||||
pub mod common;
|
||||
pub mod live_link_server;
|
||||
pub mod face_transform_rotation;
|
||||
pub mod face_data_object;
|
||||
pub mod face_bone;
|
||||
pub mod face_property;
|
||||
91
src/live_link_server.rs
Normal file
91
src/live_link_server.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
use std::borrow::BorrowMut;
|
||||
|
||||
use godot::engine::global::Error;
|
||||
use godot::engine::{Node, UdpServer};
|
||||
use godot::obj::WithBaseField;
|
||||
use godot::prelude::*;
|
||||
use live_link_face::LiveLinkFace;
|
||||
|
||||
use crate::face_data_object::{read_face_data, FaceDataObject};
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=Node)]
|
||||
pub struct LiveLinkServer {
|
||||
#[export]
|
||||
listen_ip: GString,
|
||||
#[export]
|
||||
listen_port: u16,
|
||||
udp_server: Gd<UdpServer>,
|
||||
|
||||
pub face_data: Option<LiveLinkFace>,
|
||||
|
||||
base: Base<Node>,
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl LiveLinkServer {
|
||||
#[signal]
|
||||
fn face_data_updated(changed: bool, fd: Option<Gd<FaceDataObject>>);
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl INode for LiveLinkServer {
|
||||
fn init(base: Base<Node>) -> Self {
|
||||
let server = UdpServer::new_gd();
|
||||
|
||||
Self {
|
||||
listen_ip: "100.64.0.2".into(),
|
||||
listen_port: 3011,
|
||||
udp_server: server,
|
||||
face_data: None,
|
||||
base,
|
||||
}
|
||||
}
|
||||
|
||||
fn ready(&mut self) {
|
||||
let err = self
|
||||
.udp_server
|
||||
.listen_ex(self.listen_port)
|
||||
.bind_address(self.listen_ip.clone())
|
||||
.done();
|
||||
|
||||
match err {
|
||||
Error::OK => {}
|
||||
_ => godot_error!("UdpServer listen error"),
|
||||
};
|
||||
}
|
||||
|
||||
fn enter_tree(&mut self) {}
|
||||
|
||||
fn process(&mut self, _delta: f64) {
|
||||
self.udp_server.poll();
|
||||
|
||||
if self.udp_server.is_connection_available() {
|
||||
if let Some(mut peer) = self.udp_server.take_connection() {
|
||||
let packet = peer.get_packet();
|
||||
|
||||
let (has_data, face_data) = LiveLinkFace::decode(packet.as_slice());
|
||||
if has_data {
|
||||
self.borrow_mut().face_data = Some(face_data);
|
||||
let mut face_data_object = FaceDataObject::new_gd();
|
||||
read_face_data(
|
||||
&mut face_data_object,
|
||||
&self.borrow_mut().face_data.take().unwrap(),
|
||||
);
|
||||
let fdo_variant = Variant::from(Some(face_data_object));
|
||||
let changed = Variant::from(has_data);
|
||||
self.base_mut()
|
||||
.emit_signal("face_data_updated".into(), &[changed, fdo_variant]);
|
||||
} else {
|
||||
self.borrow_mut().face_data = None;
|
||||
let changed = Variant::from(has_data);
|
||||
let fdo_variant = Variant::from::<Option<Gd<FaceDataObject>>>(None);
|
||||
self.base_mut()
|
||||
.emit_signal("face_data_updated".into(), &[changed, fdo_variant]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn exit_tree(&mut self) {}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue