Skip to content

Commit

Permalink
refactor!: replace nalgebra with glam
Browse files Browse the repository at this point in the history
  • Loading branch information
decahedron1 committed Oct 26, 2024
1 parent 2a10069 commit 18c090d
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 67 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,18 @@ rust-version = "1.70"

[features]
default = []
serde = [ "dep:serde", "nalgebra/serde-serialize" ]
serde = [ "dep:serde", "glam/serde" ]

[dependencies]
nalgebra = "0.32"
glam = "0.29"
nom = { version = "7.1", default-features = false, features = [ "alloc" ] }
serde = { version = "1.0", optional = true, features = [ "derive" ] }
tokio = { version = "1.30", features = [ "net" ] }
tokio-stream = "0.1"
thiserror = "1.0"

[dev-dependencies]
glam = { version = "0.29", features = [ "approx" ] }
tokio = { version = "1.30", features = [ "net", "macros", "signal", "rt-multi-thread" ] }
tokio-test = "0.4"
approx = "0.5"
Expand Down
13 changes: 7 additions & 6 deletions examples/performer.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::time::Instant;

use glam::EulerRot;
use vmc::{
UnitQuaternion, VMCApplyBlendShapes, VMCBlendShape, VMCBoneTransform, VMCModelState, VMCResult, VMCStandardVRM0Bone, VMCStandardVRMBlendShape, VMCState,
VMCTime, Vector3
Quat, VMCApplyBlendShapes, VMCBlendShape, VMCBoneTransform, VMCModelState, VMCResult, VMCStandardVRM0Bone, VMCStandardVRMBlendShape, VMCState, VMCTime,
Vec3
};

#[tokio::main]
Expand All @@ -19,15 +20,15 @@ async fn main() -> VMCResult<()> {
socket
.send(VMCBoneTransform::new(
VMCStandardVRM0Bone::LeftEye,
Vector3::new(-0.016136881, 0.061875343, 0.02154272),
UnitQuaternion::from_euler_angles((start.elapsed().as_secs_f32().cos()) * 0.05, (start.elapsed().as_secs_f32().sin()) * 0.05, 0.)
Vec3::new(-0.016136881, 0.061875343, 0.02154272),
Quat::from_euler(EulerRot::XYZ, (start.elapsed().as_secs_f32().cos()) * 0.05, (start.elapsed().as_secs_f32().sin()) * 0.05, 0.)
))
.await?;
socket
.send(VMCBoneTransform::new(
VMCStandardVRM0Bone::RightEye,
Vector3::new(0.016136864, 0.061875224, 0.02154272),
UnitQuaternion::from_euler_angles((start.elapsed().as_secs_f32().cos()) * 0.05, (start.elapsed().as_secs_f32().sin()) * 0.05, 0.)
Vec3::new(0.016136864, 0.061875224, 0.02154272),
Quat::from_euler(EulerRot::XYZ, (start.elapsed().as_secs_f32().cos()) * 0.05, (start.elapsed().as_secs_f32().sin()) * 0.05, 0.)
))
.await?;
socket.send(VMCApplyBlendShapes).await?;
Expand Down
5 changes: 1 addition & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,7 @@ pub mod message;
pub mod osc;
mod udp;

pub use nalgebra::{
Scale3, Vector3,
geometry::{Quaternion, UnitQuaternion}
};
pub use glam::{EulerRot, Quat, Vec3, Vec3A};

use self::udp::UDPSocketStream;
pub use self::{
Expand Down
103 changes: 48 additions & 55 deletions src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::{str::FromStr, sync::OnceLock, time::Instant};

use nalgebra::{Quaternion, Scale3, UnitQuaternion, Vector3};
use glam::{Quat, Vec3A};

use crate::{IntoOSCMessage, OSCPacket, OSCType, VMCError, VMCResult, osc::OSCMessage};

Expand All @@ -12,15 +12,15 @@ use crate::{IntoOSCMessage, OSCPacket, OSCType, VMCError, VMCResult, osc::OSCMes
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RootTransform {
pub position: Vector3<f32>,
pub rotation: UnitQuaternion<f32>,
pub scale: Option<Scale3<f32>>,
pub offset: Option<Vector3<f32>>
pub position: Vec3A,
pub rotation: Quat,
pub scale: Option<Vec3A>,
pub offset: Option<Vec3A>
}

impl RootTransform {
/// Creates a new root transform message.
pub fn new(position: impl Into<Vector3<f32>>, rotation: UnitQuaternion<f32>) -> Self {
pub fn new(position: impl Into<Vec3A>, rotation: Quat) -> Self {
Self {
position: position.into(),
rotation,
Expand All @@ -31,29 +31,27 @@ impl RootTransform {

/// Creates a new root transform message with additional scale & offset parameters, which can be used to adjust the
/// size and position of the virtual avatar to match the physical body.
pub fn new_mr(position: impl Into<Vector3<f32>>, rotation: UnitQuaternion<f32>, scale: Scale3<f32>, offset: Vector3<f32>) -> Self {
let rotation = rotation.slerp(&rotation, 1.0);
pub fn new_mr(position: impl Into<Vec3A>, rotation: Quat, scale: impl Into<Vec3A>, offset: impl Into<Vec3A>) -> Self {
Self {
position: position.into(),
rotation,
scale: Some(scale),
offset: Some(offset)
scale: Some(scale.into()),
offset: Some(offset.into())
}
}
}

impl IntoOSCMessage for RootTransform {
fn into_osc_message(self) -> crate::osc::OSCMessage {
let rotation = self.rotation.as_ref();
let mut args: Vec<OSCType> = vec![
"root".into(),
self.position.x.into(),
self.position.y.into(),
self.position.z.into(),
rotation.coords.x.into(),
rotation.coords.y.into(),
rotation.coords.z.into(),
rotation.coords.w.into(),
self.rotation.x.into(),
self.rotation.y.into(),
self.rotation.z.into(),
self.rotation.w.into(),
];
if let (Some(scale), Some(offset)) = (self.scale.as_ref(), self.offset.as_ref()) {
args.extend([scale.x.into(), scale.y.into(), scale.z.into()]);
Expand Down Expand Up @@ -290,15 +288,15 @@ impl PartialEq<StandardVRM0Bone> for String {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BoneTransform {
pub bone: String,
pub position: Vector3<f32>,
pub rotation: UnitQuaternion<f32>
pub position: Vec3A,
pub rotation: Quat
}

impl BoneTransform {
/// Creates a new bone transform message.
///
/// `bone` is the name of the bone; see [`StandardVRM0Bone`] for standard VRM 0.x bone names.
pub fn new(bone: impl ToString, position: impl Into<Vector3<f32>>, rotation: UnitQuaternion<f32>) -> Self {
pub fn new(bone: impl ToString, position: impl Into<Vec3A>, rotation: Quat) -> Self {
Self {
bone: bone.to_string(),
position: position.into(),
Expand All @@ -309,10 +307,9 @@ impl BoneTransform {

impl IntoOSCMessage for BoneTransform {
fn into_osc_message(self) -> crate::osc::OSCMessage {
let rotation = self.rotation.as_ref();
OSCMessage::new(
"/VMC/Ext/Bone/Pos",
(self.bone, self.position.x, self.position.y, self.position.z, rotation.coords.x, rotation.coords.y, rotation.coords.z, rotation.coords.w)
(self.bone, self.position.x, self.position.y, self.position.z, self.rotation.x, self.rotation.y, self.rotation.z, self.rotation.w)
)
}
}
Expand Down Expand Up @@ -361,8 +358,8 @@ impl FromStr for DeviceType {
pub struct DeviceTransform {
pub device: DeviceType,
pub joint: String,
pub position: Vector3<f32>,
pub rotation: UnitQuaternion<f32>,
pub position: Vec3A,
pub rotation: Quat,
pub local: bool
}

Expand All @@ -371,7 +368,7 @@ impl DeviceTransform {
///
/// - `joint` is the OpenVR serial no.
/// - `local` determines whether the position is in raw device scale (`true`) or avatar scale (`false`).
pub fn new(device: DeviceType, joint: impl ToString, position: impl Into<Vector3<f32>>, rotation: UnitQuaternion<f32>, local: bool) -> Self {
pub fn new(device: DeviceType, joint: impl ToString, position: impl Into<Vec3A>, rotation: Quat, local: bool) -> Self {
Self {
device,
joint: joint.to_string(),
Expand All @@ -384,10 +381,9 @@ impl DeviceTransform {

impl IntoOSCMessage for DeviceTransform {
fn into_osc_message(self) -> crate::osc::OSCMessage {
let rotation = self.rotation.as_ref();
OSCMessage::new(
format!("/VMC/Ext/{}/Pos{}", self.device.as_ref(), if self.local { "/Local" } else { "" }),
(self.joint, self.position.x, self.position.y, self.position.z, rotation.coords.x, rotation.coords.y, rotation.coords.z, rotation.coords.w)
(self.joint, self.position.x, self.position.y, self.position.z, self.rotation.x, self.rotation.y, self.rotation.z, self.rotation.w)
)
}
}
Expand Down Expand Up @@ -823,10 +819,7 @@ pub fn parse(osc_packet: OSCPacket) -> VMCResult<Vec<VMCMessage>> {
OSCType::Float(r_z),
OSCType::Float(r_w)
]
) => Ok(VMCMessage::RootTransform(RootTransform::new(
Vector3::new(p_x, p_y, p_z),
UnitQuaternion::new_unchecked(Quaternion::new(r_w, r_x, r_y, r_z))
))),
) => Ok(VMCMessage::RootTransform(RootTransform::new(Vec3A::new(p_x, p_y, p_z), Quat::from_array([r_x, r_y, r_z, r_w])))),
(
"/VMC/Ext/Root/Pos",
&[
Expand All @@ -847,10 +840,10 @@ pub fn parse(osc_packet: OSCPacket) -> VMCResult<Vec<VMCMessage>> {
..
]
) => Ok(VMCMessage::RootTransform(RootTransform::new_mr(
Vector3::new(p_x, p_y, p_z),
UnitQuaternion::new_unchecked(Quaternion::new(r_w, r_x, r_y, r_z)),
Scale3::new(s_x, s_y, s_z),
Vector3::new(o_x, o_y, o_z)
Vec3A::new(p_x, p_y, p_z),
Quat::from_array([r_x, r_y, r_z, r_w]),
Vec3A::new(s_x, s_y, s_z),
Vec3A::new(o_x, o_y, o_z)
))),
(
"/VMC/Ext/Bone/Pos",
Expand All @@ -866,8 +859,8 @@ pub fn parse(osc_packet: OSCPacket) -> VMCResult<Vec<VMCMessage>> {
]
) => Ok(VMCMessage::BoneTransform(BoneTransform::new(
StandardVRM0Bone::from_str(bone).map_err(|_| VMCError::UnknownBone(bone.to_string()))?,
Vector3::new(p_x, p_y, p_z),
UnitQuaternion::new_unchecked(Quaternion::new(r_w, r_x, r_y, r_z))
Vec3A::new(p_x, p_y, p_z),
Quat::from_array([r_x, r_y, r_z, r_w])
))),
(
"/VMC/Ext/Hmd/Pos",
Expand All @@ -885,8 +878,8 @@ pub fn parse(osc_packet: OSCPacket) -> VMCResult<Vec<VMCMessage>> {
) => Ok(VMCMessage::DeviceTransform(DeviceTransform::new(
DeviceType::HMD,
joint.to_owned(),
Vector3::new(p_x, p_y, p_z),
UnitQuaternion::new_unchecked(Quaternion::new(r_w, r_x, r_y, r_z)),
Vec3A::new(p_x, p_y, p_z),
Quat::from_array([r_x, r_y, r_z, r_w]),
false
))),
(
Expand All @@ -905,8 +898,8 @@ pub fn parse(osc_packet: OSCPacket) -> VMCResult<Vec<VMCMessage>> {
) => Ok(VMCMessage::DeviceTransform(DeviceTransform::new(
DeviceType::HMD,
joint.to_owned(),
Vector3::new(p_x, p_y, p_z),
UnitQuaternion::new_unchecked(Quaternion::new(r_w, r_x, r_y, r_z)),
Vec3A::new(p_x, p_y, p_z),
Quat::from_array([r_x, r_y, r_z, r_w]),
true
))),
(
Expand All @@ -925,8 +918,8 @@ pub fn parse(osc_packet: OSCPacket) -> VMCResult<Vec<VMCMessage>> {
) => Ok(VMCMessage::DeviceTransform(DeviceTransform::new(
DeviceType::Controller,
joint.to_owned(),
Vector3::new(p_x, p_y, p_z),
UnitQuaternion::new_unchecked(Quaternion::new(r_w, r_x, r_y, r_z)),
Vec3A::new(p_x, p_y, p_z),
Quat::from_array([r_x, r_y, r_z, r_w]),
false
))),
(
Expand All @@ -945,8 +938,8 @@ pub fn parse(osc_packet: OSCPacket) -> VMCResult<Vec<VMCMessage>> {
) => Ok(VMCMessage::DeviceTransform(DeviceTransform::new(
DeviceType::Controller,
joint.to_owned(),
Vector3::new(p_x, p_y, p_z),
UnitQuaternion::new_unchecked(Quaternion::new(r_w, r_x, r_y, r_z)),
Vec3A::new(p_x, p_y, p_z),
Quat::from_array([r_x, r_y, r_z, r_w]),
true
))),
(
Expand All @@ -965,8 +958,8 @@ pub fn parse(osc_packet: OSCPacket) -> VMCResult<Vec<VMCMessage>> {
) => Ok(VMCMessage::DeviceTransform(DeviceTransform::new(
DeviceType::Tracker,
joint.to_owned(),
Vector3::new(p_x, p_y, p_z),
UnitQuaternion::new_unchecked(Quaternion::new(r_w, r_x, r_y, r_z)),
Vec3A::new(p_x, p_y, p_z),
Quat::from_array([r_x, r_y, r_z, r_w]),
false
))),
(
Expand All @@ -985,8 +978,8 @@ pub fn parse(osc_packet: OSCPacket) -> VMCResult<Vec<VMCMessage>> {
) => Ok(VMCMessage::DeviceTransform(DeviceTransform::new(
DeviceType::Tracker,
joint.to_owned(),
Vector3::new(p_x, p_y, p_z),
UnitQuaternion::new_unchecked(Quaternion::new(r_w, r_x, r_y, r_z)),
Vec3A::new(p_x, p_y, p_z),
Quat::from_array([r_x, r_y, r_z, r_w]),
true
))),
("/VMC/Ext/Blend/Val", &[OSCType::String(ref shape), OSCType::Float(val), ..]) => Ok(VMCMessage::BlendShape(BlendShape::new(shape, val))),
Expand Down Expand Up @@ -1029,10 +1022,10 @@ mod tests {

#[test]
fn test_parse_root_transform() -> VMCResult<()> {
let position = Vector3::new(0.5, 0.2, -0.4);
let rotation = UnitQuaternion::new_normalize(Quaternion::new(1.0, 2.0, 3.0, 4.0));
let scale = Scale3::new(0.8, 1.0, 0.3);
let offset = Vector3::new(-0.1, 0.12, -0.3);
let position = Vec3A::new(0.5, 0.2, -0.4);
let rotation = Quat::from_array([1.0, 2.0, 3.0, 4.0]).normalize();
let scale = Vec3A::new(0.8, 1.0, 0.3);
let offset = Vec3A::new(-0.1, 0.12, -0.3);

let packet = RootTransform::new(position, rotation).into_osc_packet();
let parsed_packet = &parse(packet)?[0];
Expand Down Expand Up @@ -1063,8 +1056,8 @@ mod tests {

#[test]
fn test_parse_bone_transform() -> VMCResult<()> {
let position = Vector3::new(0.5, 0.2, -0.4);
let rotation = UnitQuaternion::new_normalize(Quaternion::new(1.0, 2.0, 3.0, 4.0));
let position = Vec3A::new(0.5, 0.2, -0.4);
let rotation = Quat::from_array([1.0, 2.0, 3.0, 4.0]).normalize();

for bone in [
StandardVRM0Bone::Chest,
Expand All @@ -1090,8 +1083,8 @@ mod tests {

#[test]
fn test_parse_device_transform() -> VMCResult<()> {
let position = Vector3::new(0.5, 0.2, -0.4);
let rotation = UnitQuaternion::new_normalize(Quaternion::new(1.0, 2.0, 3.0, 4.0));
let position = Vec3A::new(0.5, 0.2, -0.4);
let rotation = Quat::from_array([1.0, 2.0, 3.0, 4.0]).normalize();

for device in [DeviceType::HMD, DeviceType::Controller, DeviceType::Tracker] {
for joint in ["Head", "LeftHand"] {
Expand Down

0 comments on commit 18c090d

Please sign in to comment.