From c316eee929886b4eec5f3d1cc14b2616da877431 Mon Sep 17 00:00:00 2001 From: Malcolm Nixon Date: Mon, 15 Jan 2024 23:35:51 -0500 Subject: [PATCH] Add bone update option to OpenXRHand to allow preserving original hand scale. This is useful if the hand model is not weighted to support re-scaling to the users hands; or the hand is scaled to non-human sizes. --- modules/openxr/doc_classes/OpenXRHand.xml | 13 ++++++++++++ modules/openxr/scene/openxr_hand.cpp | 26 +++++++++++++++++++++-- modules/openxr/scene/openxr_hand.h | 11 ++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/modules/openxr/doc_classes/OpenXRHand.xml b/modules/openxr/doc_classes/OpenXRHand.xml index eb7decd30d49..1c4da8313886 100644 --- a/modules/openxr/doc_classes/OpenXRHand.xml +++ b/modules/openxr/doc_classes/OpenXRHand.xml @@ -7,10 +7,14 @@ This node enables OpenXR's hand tracking functionality. The node should be a child node of an [XROrigin3D] node, tracking will update its position to the player's tracked hand Palm joint location (the center of the middle finger's metacarpal bone). This node also updates the skeleton of a properly skinned hand or avatar model. If the skeleton is a hand (one of the hand bones is the root node of the skeleton), then the skeleton will be placed relative to the hand palm location and the hand mesh and skeleton should be children of the OpenXRHand node. If the hand bones are part of a full skeleton, then the root of the hand will keep its location with the assumption that IK is used to position the hand and arm. + By default the skeleton hand bones are repositioned to match the size of the tracked hand. To preserve the modeled bone sizes change [member bone_update] to apply rotation only. + + Specify the type of updates to perform on the bone. + Specifies whether this node tracks the left or right hand of the player. @@ -52,5 +56,14 @@ Maximum supported hands. + + The skeletons bones are fully updated (both position and rotation) to match the tracked bones. + + + The skeletons bones are only rotated to align with the tracked bones, preserving bone length. + + + Maximum supported bone update mode. + diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp index 8ce33b55c3aa..2a4104f6eef1 100644 --- a/modules/openxr/scene/openxr_hand.cpp +++ b/modules/openxr/scene/openxr_hand.cpp @@ -49,10 +49,14 @@ void OpenXRHand::_bind_methods() { ClassDB::bind_method(D_METHOD("set_skeleton_rig", "skeleton_rig"), &OpenXRHand::set_skeleton_rig); ClassDB::bind_method(D_METHOD("get_skeleton_rig"), &OpenXRHand::get_skeleton_rig); + ClassDB::bind_method(D_METHOD("set_bone_update", "bone_update"), &OpenXRHand::set_bone_update); + ClassDB::bind_method(D_METHOD("get_bone_update"), &OpenXRHand::get_bone_update); + ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Left,Right"), "set_hand", "get_hand"); ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_range", PROPERTY_HINT_ENUM, "Unobstructed,Conform to controller"), "set_motion_range", "get_motion_range"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "hand_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_hand_skeleton", "get_hand_skeleton"); ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton_rig", PROPERTY_HINT_ENUM, "OpenXR,Humanoid"), "set_skeleton_rig", "get_skeleton_rig"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_update", PROPERTY_HINT_ENUM, "Full,Rotation Only"), "set_bone_update", "get_bone_update"); BIND_ENUM_CONSTANT(HAND_LEFT); BIND_ENUM_CONSTANT(HAND_RIGHT); @@ -65,6 +69,10 @@ void OpenXRHand::_bind_methods() { BIND_ENUM_CONSTANT(SKELETON_RIG_OPENXR); BIND_ENUM_CONSTANT(SKELETON_RIG_HUMANOID); BIND_ENUM_CONSTANT(SKELETON_RIG_MAX); + + BIND_ENUM_CONSTANT(BONE_UPDATE_FULL); + BIND_ENUM_CONSTANT(BONE_UPDATE_ROTATION_ONLY); + BIND_ENUM_CONSTANT(BONE_UPDATE_MAX); } OpenXRHand::OpenXRHand() { @@ -134,6 +142,16 @@ OpenXRHand::SkeletonRig OpenXRHand::get_skeleton_rig() const { return skeleton_rig; } +void OpenXRHand::set_bone_update(BoneUpdate p_bone_update) { + ERR_FAIL_INDEX(p_bone_update, BONE_UPDATE_MAX); + + bone_update = p_bone_update; +} + +OpenXRHand::BoneUpdate OpenXRHand::get_bone_update() const { + return bone_update; +} + Skeleton3D *OpenXRHand::get_skeleton() { if (!has_node(hand_skeleton)) { return nullptr; @@ -346,8 +364,12 @@ void OpenXRHand::_update_skeleton() { const Quaternion q = inv_quaternions[parent_joint] * quaternions[joint]; const Vector3 p = inv_quaternions[parent_joint].xform(positions[joint] - positions[parent_joint]); - // and set our pose - skeleton->set_bone_pose_position(joints[joint].bone, p); + // Update the bone position if enabled by update mode. + if (bone_update == BONE_UPDATE_FULL) { + skeleton->set_bone_pose_position(joints[joint].bone, p); + } + + // Always update the bone rotation. skeleton->set_bone_pose_rotation(joints[joint].bone, q); } diff --git a/modules/openxr/scene/openxr_hand.h b/modules/openxr/scene/openxr_hand.h index 14eb893bcc0c..4c77e7277c84 100644 --- a/modules/openxr/scene/openxr_hand.h +++ b/modules/openxr/scene/openxr_hand.h @@ -61,6 +61,12 @@ public: SKELETON_RIG_MAX }; + enum BoneUpdate { + BONE_UPDATE_FULL, + BONE_UPDATE_ROTATION_ONLY, + BONE_UPDATE_MAX + }; + private: struct JointData { int bone = -1; @@ -74,6 +80,7 @@ private: MotionRange motion_range = MOTION_RANGE_UNOBSTRUCTED; NodePath hand_skeleton; SkeletonRig skeleton_rig = SKELETON_RIG_OPENXR; + BoneUpdate bone_update = BONE_UPDATE_FULL; JointData joints[XR_HAND_JOINT_COUNT_EXT]; @@ -101,11 +108,15 @@ public: void set_skeleton_rig(SkeletonRig p_skeleton_rig); SkeletonRig get_skeleton_rig() const; + void set_bone_update(BoneUpdate p_bone_update); + BoneUpdate get_bone_update() const; + void _notification(int p_what); }; VARIANT_ENUM_CAST(OpenXRHand::Hands) VARIANT_ENUM_CAST(OpenXRHand::MotionRange) VARIANT_ENUM_CAST(OpenXRHand::SkeletonRig) +VARIANT_ENUM_CAST(OpenXRHand::BoneUpdate) #endif // OPENXR_HAND_H