From 823ae7b3fa25832d1cd9d7613c650bfc712d1f49 Mon Sep 17 00:00:00 2001 From: Malcolm Nixon Date: Sat, 13 Apr 2024 17:26:46 -0400 Subject: [PATCH] Rework XR Trackers to have a common ancestor. Allow creation of XRNode3D to drive node positions and visibility. --- doc/classes/XRBodyModifier3D.xml | 9 +- doc/classes/XRBodyTracker.xml | 3 +- doc/classes/XRControllerTracker.xml | 17 ++ doc/classes/XRFaceModifier3D.xml | 2 +- doc/classes/XRFaceTracker.xml | 3 +- doc/classes/XRHandModifier3D.xml | 6 +- doc/classes/XRHandTracker.xml | 19 +- doc/classes/XRNode3D.xml | 3 + doc/classes/XRPositionalTracker.xml | 22 +-- doc/classes/XRServer.xml | 163 ++---------------- doc/classes/XRTracker.xml | 30 ++++ editor/icons/XRFaceModifier3D.svg | 1 + editor/icons/XRNode3D.svg | 1 + .../4.2-stable.expected | 21 +++ .../openxr/doc_classes/OpenXRInterface.xml | 14 +- .../openxr_hand_tracking_extension.cpp | 33 ++-- modules/openxr/openxr_interface.cpp | 69 ++++---- modules/openxr/openxr_interface.h | 4 +- modules/webxr/doc_classes/WebXRInterface.xml | 4 +- modules/webxr/webxr_interface.compat.inc | 41 +++++ modules/webxr/webxr_interface.cpp | 1 + modules/webxr/webxr_interface.h | 9 +- modules/webxr/webxr_interface_js.cpp | 14 +- modules/webxr/webxr_interface_js.h | 6 +- scene/3d/xr_body_modifier_3d.cpp | 45 +---- scene/3d/xr_body_modifier_3d.h | 6 +- scene/3d/xr_face_modifier_3d.cpp | 8 +- scene/3d/xr_face_modifier_3d.h | 2 +- scene/3d/xr_hand_modifier_3d.cpp | 111 ++++++------ scene/3d/xr_hand_modifier_3d.h | 4 +- scene/3d/xr_nodes.cpp | 37 +++- scene/3d/xr_nodes.h | 4 + scene/register_scene_types.cpp | 2 +- servers/register_server_types.cpp | 3 + servers/xr/xr_body_tracker.cpp | 12 ++ servers/xr/xr_body_tracker.h | 11 +- servers/xr/xr_controller_tracker.cpp | 39 +++++ servers/xr/xr_controller_tracker.h | 52 ++++++ servers/xr/xr_face_tracker.cpp | 8 + servers/xr/xr_face_tracker.h | 10 +- servers/xr/xr_hand_tracker.cpp | 50 +++++- servers/xr/xr_hand_tracker.h | 11 +- servers/xr/xr_positional_tracker.cpp | 73 ++------ servers/xr/xr_positional_tracker.h | 28 +-- servers/xr/xr_tracker.cpp | 70 ++++++++ servers/xr/xr_tracker.h | 61 +++++++ servers/xr_server.compat.inc | 51 ++++++ servers/xr_server.cpp | 163 ++---------------- servers/xr_server.h | 49 ++---- 49 files changed, 769 insertions(+), 636 deletions(-) create mode 100644 doc/classes/XRControllerTracker.xml create mode 100644 doc/classes/XRTracker.xml create mode 100644 editor/icons/XRFaceModifier3D.svg create mode 100644 editor/icons/XRNode3D.svg create mode 100644 modules/webxr/webxr_interface.compat.inc create mode 100644 servers/xr/xr_controller_tracker.cpp create mode 100644 servers/xr/xr_controller_tracker.h create mode 100644 servers/xr/xr_tracker.cpp create mode 100644 servers/xr/xr_tracker.h create mode 100644 servers/xr_server.compat.inc diff --git a/doc/classes/XRBodyModifier3D.xml b/doc/classes/XRBodyModifier3D.xml index 49a226c1060..d08b92a56c8 100644 --- a/doc/classes/XRBodyModifier3D.xml +++ b/doc/classes/XRBodyModifier3D.xml @@ -4,15 +4,15 @@ A node for driving body meshes from [XRBodyTracker] data. - This node uses body tracking data from a [XRBodyTracker] to animate the skeleton of a body mesh. - This node positions itself at the [constant XRBodyTracker.JOINT_ROOT] position and scales itself to [member XRServer.world_scale]. Adding the body model as a child of this node will result in the model being positioned and scaled correctly for XR experiences. + This node uses body tracking data from an [XRBodyTracker] to pose the skeleton of a body mesh. + Positioning of the body is performed by creating an [XRNode3D] ancestor of the body mesh driven by the same [XRBodyTracker]. The body tracking position-data is scaled by [member Skeleton3D.motion_scale] when applied to the skeleton, which can be used to adjust the tracked body to match the scale of the body model. $DOCS_URL/tutorials/xr/index.html - + The name of the [XRBodyTracker] registered with [XRServer] to obtain the body tracking data from. @@ -21,9 +21,6 @@ Specifies the type of updates to perform on the bones. - - If true then the nodes visibility is determined by whether tracking data is available. - diff --git a/doc/classes/XRBodyTracker.xml b/doc/classes/XRBodyTracker.xml index 9c869b4f5f3..06a48799531 100644 --- a/doc/classes/XRBodyTracker.xml +++ b/doc/classes/XRBodyTracker.xml @@ -1,5 +1,5 @@ - + A tracked body in XR. @@ -49,6 +49,7 @@ If [code]true[/code], the body tracking data is valid. + diff --git a/doc/classes/XRControllerTracker.xml b/doc/classes/XRControllerTracker.xml new file mode 100644 index 00000000000..50727a7633a --- /dev/null +++ b/doc/classes/XRControllerTracker.xml @@ -0,0 +1,17 @@ + + + + A tracked controller. + + + An instance of this object represents a controller that is tracked. + As controllers are turned on and the [XRInterface] detects them, instances of this object are automatically added to this list of active tracking objects accessible through the [XRServer]. + The [XRController3D] consumes objects of this type and should be used in your project. + + + $DOCS_URL/tutorials/xr/index.html + + + + + diff --git a/doc/classes/XRFaceModifier3D.xml b/doc/classes/XRFaceModifier3D.xml index 8caa74cff7d..9599051b1b8 100644 --- a/doc/classes/XRFaceModifier3D.xml +++ b/doc/classes/XRFaceModifier3D.xml @@ -12,7 +12,7 @@ $DOCS_URL/tutorials/xr/index.html - + The [XRFaceTracker] path. diff --git a/doc/classes/XRFaceTracker.xml b/doc/classes/XRFaceTracker.xml index 96ed137324d..23a9a9cb171 100644 --- a/doc/classes/XRFaceTracker.xml +++ b/doc/classes/XRFaceTracker.xml @@ -1,5 +1,5 @@ - + A tracked face. @@ -31,6 +31,7 @@ The array of face blend shape weights with indices corresponding to the [enum BlendShapeEntry] enum. + diff --git a/doc/classes/XRHandModifier3D.xml b/doc/classes/XRHandModifier3D.xml index 9ff27bb9820..09ff3210707 100644 --- a/doc/classes/XRHandModifier3D.xml +++ b/doc/classes/XRHandModifier3D.xml @@ -4,8 +4,8 @@ A node for driving hand meshes from [XRHandTracker] data. - This node uses hand tracking data from a [XRHandTracker] to animate the skeleton of a hand mesh. - This node positions itself at the [constant XRHandTracker.HAND_JOINT_PALM] position and scales itself to [member XRServer.world_scale]. Adding the hand model as a child of this node will result in the model being positioned and scaled correctly for XR experiences. + This node uses hand tracking data from an [XRHandTracker] to pose the skeleton of a hand mesh. + Positioning of hands is performed by creating an [XRNode3D] ancestor of the hand mesh driven by the same [XRHandTracker]. The hand tracking position-data is scaled by [member Skeleton3D.motion_scale] when applied to the skeleton, which can be used to adjust the tracked hand to match the scale of the hand model. @@ -15,7 +15,7 @@ Specifies the type of updates to perform on the bones. - + The name of the [XRHandTracker] registered with [XRServer] to obtain the hand tracking data from. diff --git a/doc/classes/XRHandTracker.xml b/doc/classes/XRHandTracker.xml index 932fec083a2..69390df696b 100644 --- a/doc/classes/XRHandTracker.xml +++ b/doc/classes/XRHandTracker.xml @@ -1,5 +1,5 @@ - + A tracked hand in XR. @@ -11,6 +11,12 @@ $DOCS_URL/tutorials/xr/index.html + + + + Returns the type of hand. + + @@ -46,6 +52,13 @@ Returns the transform for the given hand joint. + + + + + Sets the type of hand. + + @@ -88,15 +101,13 @@ - - The type of hand. - The source of the hand tracking data. If [code]true[/code], the hand tracking data is valid. + diff --git a/doc/classes/XRNode3D.xml b/doc/classes/XRNode3D.xml index 3da1873ed81..dfe5600fcc9 100644 --- a/doc/classes/XRNode3D.xml +++ b/doc/classes/XRNode3D.xml @@ -46,6 +46,9 @@ The name of the pose we're bound to. Which poses a tracker supports is not known during design time. Godot defines number of standard pose names such as [code]aim[/code] and [code]grip[/code] but other may be configured within a given [XRInterface]. + + Enables showing the node when tracking starts, and hiding the node when tracking is lost. + The name of the tracker we're bound to. Which trackers are available is not known during design time. Godot defines a number of standard trackers such as [code]left_hand[/code] and [code]right_hand[/code] but others may be configured within a given [XRInterface]. diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml index bd2432af50c..2b2eae0c5e0 100644 --- a/doc/classes/XRPositionalTracker.xml +++ b/doc/classes/XRPositionalTracker.xml @@ -1,18 +1,18 @@ - + A tracked object. An instance of this object represents a device that is tracked, such as a controller or anchor point. HMDs aren't represented here as they are handled internally. As controllers are turned on and the [XRInterface] detects them, instances of this object are automatically added to this list of active tracking objects accessible through the [XRServer]. - The [XRController3D] and [XRAnchor3D] both consume objects of this type and should be used in your project. The positional trackers are just under-the-hood objects that make this all work. These are mostly exposed so that GDExtension-based interfaces can interact with them. + The [XRNode3D] and [XRAnchor3D] both consume objects of this type and should be used in your project. The positional trackers are just under-the-hood objects that make this all work. These are mostly exposed so that GDExtension-based interfaces can interact with them. $DOCS_URL/tutorials/xr/index.html - + @@ -40,7 +40,7 @@ Marks this pose as invalid, we don't clear the last reported state but it allows users to decide if trackers need to be hidden if we lose tracking or just remain at their last known position. - + @@ -61,23 +61,12 @@ - - The description of this tracker. - Defines which hand this tracker relates to. - - The unique name of this tracker. The trackers that are available differ between various XR runtimes and can often be configured by the user. Godot maintains a number of reserved names that it expects the [XRInterface] to implement if applicable: - - [code]left_hand[/code] identifies the controller held in the players left hand - - [code]right_hand[/code] identifies the controller held in the players right hand - The profile associated with this tracker, interface dependent but will indicate the type of controller being tracked. - - The type of tracker. - @@ -135,5 +124,8 @@ This tracker is the right hand controller. + + Represents the size of the [enum TrackerHand] enum. + diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml index 671cc8f15c9..d5714980c3b 100644 --- a/doc/classes/XRServer.xml +++ b/doc/classes/XRServer.xml @@ -10,30 +10,6 @@ $DOCS_URL/tutorials/xr/index.html - - - - - - Registers a new [XRBodyTracker] that tracks the joints of a body. - - - - - - - - Registers a new [XRFaceTracker] that tracks the blend shapes of a face. - - - - - - - - Registers a new [XRHandTracker] that tracks the joints of a hand. - - @@ -43,9 +19,9 @@ - + - Registers a new [XRPositionalTracker] that tracks a spatial location in real space. + Registers a new [XRTracker] that tracks a physical object. @@ -74,45 +50,6 @@ Finds an interface by its [param name]. For example, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it. - - - - - Returns the [XRBodyTracker] with the given tracker name. - - - - - - Returns a dictionary of the registered body trackers. Each element of the dictionary is a tracker name mapping to the [XRBodyTracker] instance. - - - - - - - Returns the [XRFaceTracker] with the given tracker name. - - - - - - Returns a dictionary of the registered face trackers. Each element of the dictionary is a tracker name mapping to the [XRFaceTracker] instance. - - - - - - - Returns the [XRHandTracker] with the given tracker name. - - - - - - Returns a dictionary of the registered hand trackers. Each element of the dictionary is a tracker name mapping to the [XRHandTracker] instance. - - @@ -145,7 +82,7 @@ - + Returns the positional tracker with the given [param tracker_name]. @@ -158,27 +95,6 @@ Returns a dictionary of trackers for [param tracker_types]. - - - - - Removes a registered [XRBodyTracker]. - - - - - - - Removes a registered [XRFaceTracker]. - - - - - - - Removes a registered [XRHandTracker]. - - @@ -188,9 +104,9 @@ - + - Removes this positional [param tracker]. + Removes this [param tracker]. @@ -207,66 +123,6 @@ - - - - - Emitted when a new body tracker is added. - - - - - - Emitted when a body tracker is removed. - - - - - - - Emitted when an existing body tracker is updated. - - - - - - - Emitted when a new face tracker is added. - - - - - - Emitted when a face tracker is removed. - - - - - - - Emitted when an existing face tracker is updated. - - - - - - - Emitted when a new hand tracker is added. - - - - - - Emitted when a hand tracker is removed. - - - - - - - Emitted when an existing hand tracker is updated. - - @@ -314,6 +170,15 @@ The tracker tracks the location and size of an AR anchor. + + The tracker tracks the location and joints of a hand. + + + The tracker tracks the location and joints of a body. + + + The tracker tracks the expressions of a face. + Used internally to filter trackers of any known type. diff --git a/doc/classes/XRTracker.xml b/doc/classes/XRTracker.xml new file mode 100644 index 00000000000..00a44bd03eb --- /dev/null +++ b/doc/classes/XRTracker.xml @@ -0,0 +1,30 @@ + + + + A tracked object. + + + This object is the base of all XR trackers. + + + $DOCS_URL/tutorials/xr/index.html + + + + The description of this tracker. + + + The unique name of this tracker. The trackers that are available differ between various XR runtimes and can often be configured by the user. Godot maintains a number of reserved names that it expects the [XRInterface] to implement if applicable: + - [code]head[/code] identifies the [XRPositionalTracker] of the players head + - [code]left_hand[/code] identifies the [XRControllerTracker] in the players left hand + - [code]right_hand[/code] identifies the [XRControllerTracker] in the players right hand + - [code]/user/hand_tracker/left[/code] identifies the [XRHandTracker] for the players left hand + - [code]/user/hand_tracker/right[/code] identifies the [XRHandTracker] for the players right hand + - [code]/user/body_tracker[/code] identifies the [XRBodyTracker] for the players body + - [code]/user/face_tracker[/code] identifies the [XRFaceTracker] for the players face + + + The type of tracker. + + + diff --git a/editor/icons/XRFaceModifier3D.svg b/editor/icons/XRFaceModifier3D.svg new file mode 100644 index 00000000000..6ab48ca29c9 --- /dev/null +++ b/editor/icons/XRFaceModifier3D.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/editor/icons/XRNode3D.svg b/editor/icons/XRNode3D.svg new file mode 100644 index 00000000000..50dd3ad9515 --- /dev/null +++ b/editor/icons/XRNode3D.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected index 6471c5a142f..ea9d1467f64 100644 --- a/misc/extension_api_validation/4.2-stable.expected +++ b/misc/extension_api_validation/4.2-stable.expected @@ -278,6 +278,7 @@ Validate extension JSON: API was removed: classes/Skeleton3D/signals/bone_pose_c They have been replaced by a safer API due to performance concerns. Compatibility method registered. + GH-90747 -------- Validate extension JSON: API was removed: classes/NavigationRegion2D/methods/get_avoidance_layers @@ -290,3 +291,23 @@ Validate extension JSON: API was removed: classes/NavigationRegion2D/methods/get Validate extension JSON: API was removed: classes/NavigationRegion2D/properties/constrain_avoidance Experimental NavigationRegion2D feature "constrain_avoidance" was discontinued with no replacement. + + +GH-90645 +-------- +Validate extension JSON: API was removed: classes/XRPositionalTracker/methods/get_tracker_desc +Validate extension JSON: API was removed: classes/XRPositionalTracker/methods/get_tracker_name +Validate extension JSON: API was removed: classes/XRPositionalTracker/methods/get_tracker_type +Validate extension JSON: API was removed: classes/XRPositionalTracker/methods/set_tracker_desc +Validate extension JSON: API was removed: classes/XRPositionalTracker/methods/set_tracker_name +Validate extension JSON: API was removed: classes/XRPositionalTracker/methods/set_tracker_type +Validate extension JSON: API was removed: classes/XRPositionalTracker/properties/description +Validate extension JSON: API was removed: classes/XRPositionalTracker/properties/name +Validate extension JSON: API was removed: classes/XRPositionalTracker/properties/type +Validate extension JSON: Error: Field 'classes/WebXRInterface/methods/get_input_source_tracker/return_value': type changed value in new API, from "XRPositionalTracker" to "XRControllerTracker". +Validate extension JSON: Error: Field 'classes/XRServer/methods/add_tracker/arguments/0': type changed value in new API, from "XRPositionalTracker" to "XRTracker". +Validate extension JSON: Error: Field 'classes/XRServer/methods/get_tracker/return_value': type changed value in new API, from "XRPositionalTracker" to "XRTracker". +Validate extension JSON: Error: Field 'classes/XRServer/methods/remove_tracker/arguments/0': type changed value in new API, from "XRPositionalTracker" to "XRTracker". + +All trackers now have an XRTracker base, and the XRServer uses the XRTracker type. + diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index 1136ac1b697..05dff7d6ae0 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -23,7 +23,7 @@ Returns display refresh rates supported by the current HMD. Only returned if this feature is supported by the OpenXR runtime and after the interface has been initialized. - + @@ -31,7 +31,7 @@ If handtracking is enabled, returns the angular velocity of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D]! - + @@ -39,7 +39,7 @@ If handtracking is enabled, returns flags that inform us of the validity of the tracking data. - + @@ -47,7 +47,7 @@ If handtracking is enabled, returns the linear velocity of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D] without worldscale applied! - + @@ -55,7 +55,7 @@ If handtracking is enabled, returns the position of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D] without worldscale applied! - + @@ -63,7 +63,7 @@ If handtracking is enabled, returns the radius of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is without worldscale applied! - + @@ -71,7 +71,7 @@ If handtracking is enabled, returns the rotation of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. - + diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp index b3c20ef8b91..f8cc3d1d8cf 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -196,7 +196,8 @@ void OpenXRHandTrackingExtension::on_process() { Ref godot_tracker; godot_tracker.instantiate(); godot_tracker->set_hand(i == 0 ? XRHandTracker::HAND_LEFT : XRHandTracker::HAND_RIGHT); - XRServer::get_singleton()->add_hand_tracker(i == 0 ? "/user/left" : "/user/right", godot_tracker); + godot_tracker->set_tracker_name(i == 0 ? "/user/hand_tracker/left" : "/user/hand_tracker/right"); + XRServer::get_singleton()->add_tracker(godot_tracker); hand_trackers[i].godot_tracker = godot_tracker; hand_trackers[i].is_initialized = true; @@ -229,8 +230,7 @@ void OpenXRHandTrackingExtension::on_process() { // For some reason an inactive controller isn't coming back as inactive but has coordinates either as NAN or very large const XrPosef &palm = hand_trackers[i].joint_locations[XR_HAND_JOINT_PALM_EXT].pose; - if ( - !hand_trackers[i].locations.isActive || isnan(palm.position.x) || palm.position.x < -1000000.00 || palm.position.x > 1000000.00) { + if (!hand_trackers[i].locations.isActive || isnan(palm.position.x) || palm.position.x < -1000000.00 || palm.position.x > 1000000.00) { hand_trackers[i].locations.isActive = false; // workaround, make sure its inactive } @@ -249,6 +249,8 @@ void OpenXRHandTrackingExtension::on_process() { const XrPosef &pose = location.pose; Transform3D transform; + Vector3 linear_velocity; + Vector3 angular_velocity; BitField flags; if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { @@ -269,27 +271,34 @@ void OpenXRHandTrackingExtension::on_process() { } if (location.locationFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) { flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_LINEAR_VELOCITY_VALID); - godot_tracker->set_hand_joint_linear_velocity((XRHandTracker::HandJoint)joint, Vector3(velocity.linearVelocity.x, velocity.linearVelocity.y, velocity.linearVelocity.z)); + linear_velocity = Vector3(velocity.linearVelocity.x, velocity.linearVelocity.y, velocity.linearVelocity.z); + godot_tracker->set_hand_joint_linear_velocity((XRHandTracker::HandJoint)joint, linear_velocity); } if (location.locationFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) { flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_ANGULAR_VELOCITY_VALID); - godot_tracker->set_hand_joint_angular_velocity((XRHandTracker::HandJoint)joint, Vector3(velocity.angularVelocity.x, velocity.angularVelocity.y, velocity.angularVelocity.z)); + angular_velocity = Vector3(velocity.angularVelocity.x, velocity.angularVelocity.y, velocity.angularVelocity.z); + godot_tracker->set_hand_joint_angular_velocity((XRHandTracker::HandJoint)joint, angular_velocity); } godot_tracker->set_hand_joint_flags((XRHandTracker::HandJoint)joint, flags); godot_tracker->set_hand_joint_transform((XRHandTracker::HandJoint)joint, transform); godot_tracker->set_hand_joint_radius((XRHandTracker::HandJoint)joint, location.radius); - XRHandTracker::HandTrackingSource source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN; - if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) { - source = XRHandTracker::HAND_TRACKING_SOURCE_UNOBSTRUCTED; - } else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) { - source = XRHandTracker::HAND_TRACKING_SOURCE_CONTROLLER; + if (joint == XR_HAND_JOINT_PALM_EXT) { + XRHandTracker::HandTrackingSource source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN; + if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) { + source = XRHandTracker::HAND_TRACKING_SOURCE_UNOBSTRUCTED; + } else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) { + source = XRHandTracker::HAND_TRACKING_SOURCE_CONTROLLER; + } + + godot_tracker->set_hand_tracking_source(source); + godot_tracker->set_pose("default", transform, linear_velocity, angular_velocity); } - godot_tracker->set_hand_tracking_source(source); } } else { godot_tracker->set_has_tracking_data(false); + godot_tracker->invalidate_pose("default"); } } } @@ -311,7 +320,7 @@ void OpenXRHandTrackingExtension::cleanup_hand_tracking() { hand_trackers[i].is_initialized = false; hand_trackers[i].hand_tracker = XR_NULL_HANDLE; - XRServer::get_singleton()->remove_hand_tracker(i == 0 ? "/user/left" : "/user/right"); + XRServer::get_singleton()->remove_tracker(hand_trackers[i].godot_tracker); } } } diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 7eb9a6ebe1e..aa68441f036 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -35,6 +35,7 @@ #include "servers/rendering/rendering_server_globals.h" #include "extensions/openxr_eye_gaze_interaction.h" +#include "thirdparty/openxr/include/openxr/openxr.h" void OpenXRInterface::_bind_methods() { // lifecycle signals @@ -154,9 +155,14 @@ PackedStringArray OpenXRInterface::get_suggested_tracker_names() const { // These are hardcoded in OpenXR, note that they will only be available if added to our action map PackedStringArray arr = { - "left_hand", // /user/hand/left is mapped to our defaults - "right_hand", // /user/hand/right is mapped to our defaults - "/user/treadmill", + "head", // XRPositionalTracker for the users head (Mapped from OpenXR /user/head) + "left_hand", // XRControllerTracker for the users left hand (Mapped from OpenXR /user/hand/left) + "right_hand", // XRControllerTracker for the users right hand (Mapped from OpenXR /user/hand/right) + "/user/hand_tracker/left", // XRHandTracker for the users left hand + "/user/hand_tracker/right", // XRHandTracker for the users right hand + "/user/body_tracker", // XRBodyTracker for the users body + "/user/face_tracker", // XRFaceTracker for the users face + "/user/treadmill" }; for (OpenXRExtensionWrapper *wrapper : OpenXRAPI::get_singleton()->get_registered_extension_wrappers()) { @@ -430,34 +436,31 @@ OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_tracker_ RID tracker_rid = openxr_api->tracker_create(p_tracker_name); ERR_FAIL_COND_V(tracker_rid.is_null(), nullptr); - // create our positional tracker - Ref positional_tracker; - positional_tracker.instantiate(); + // Create our controller tracker. + Ref controller_tracker; + controller_tracker.instantiate(); // We have standardized some names to make things nicer to the user so lets recognize the toplevel paths related to these. if (p_tracker_name == "/user/hand/left") { - positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); - positional_tracker->set_tracker_name("left_hand"); - positional_tracker->set_tracker_desc("Left hand controller"); - positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT); + controller_tracker->set_tracker_name("left_hand"); + controller_tracker->set_tracker_desc("Left hand controller"); + controller_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT); } else if (p_tracker_name == "/user/hand/right") { - positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); - positional_tracker->set_tracker_name("right_hand"); - positional_tracker->set_tracker_desc("Right hand controller"); - positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT); + controller_tracker->set_tracker_name("right_hand"); + controller_tracker->set_tracker_desc("Right hand controller"); + controller_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT); } else { - positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); - positional_tracker->set_tracker_name(p_tracker_name); - positional_tracker->set_tracker_desc(p_tracker_name); + controller_tracker->set_tracker_name(p_tracker_name); + controller_tracker->set_tracker_desc(p_tracker_name); } - positional_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE); - xr_server->add_tracker(positional_tracker); + controller_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE); + xr_server->add_tracker(controller_tracker); // create a new entry tracker = memnew(Tracker); tracker->tracker_name = p_tracker_name; tracker->tracker_rid = tracker_rid; - tracker->positional_tracker = positional_tracker; + tracker->controller_tracker = controller_tracker; tracker->interaction_profile = RID(); trackers.push_back(tracker); @@ -477,17 +480,17 @@ void OpenXRInterface::tracker_profile_changed(RID p_tracker, RID p_interaction_p if (p_interaction_profile.is_null()) { print_verbose("OpenXR: Interaction profile for " + tracker->tracker_name + " changed to " + INTERACTION_PROFILE_NONE); - tracker->positional_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE); + tracker->controller_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE); } else { String name = openxr_api->interaction_profile_get_name(p_interaction_profile); print_verbose("OpenXR: Interaction profile for " + tracker->tracker_name + " changed to " + name); - tracker->positional_tracker->set_tracker_profile(name); + tracker->controller_tracker->set_tracker_profile(name); } } void OpenXRInterface::handle_tracker(Tracker *p_tracker) { ERR_FAIL_NULL(openxr_api); - ERR_FAIL_COND(p_tracker->positional_tracker.is_null()); + ERR_FAIL_COND(p_tracker->controller_tracker.is_null()); // Note, which actions are actually bound to inputs are handled by our interaction profiles however interaction // profiles are suggested bindings for controller types we know about. OpenXR runtimes can stray away from these @@ -506,15 +509,15 @@ void OpenXRInterface::handle_tracker(Tracker *p_tracker) { switch (action->action_type) { case OpenXRAction::OPENXR_ACTION_BOOL: { bool pressed = openxr_api->get_action_bool(action->action_rid, p_tracker->tracker_rid); - p_tracker->positional_tracker->set_input(action->action_name, Variant(pressed)); + p_tracker->controller_tracker->set_input(action->action_name, Variant(pressed)); } break; case OpenXRAction::OPENXR_ACTION_FLOAT: { real_t value = openxr_api->get_action_float(action->action_rid, p_tracker->tracker_rid); - p_tracker->positional_tracker->set_input(action->action_name, Variant(value)); + p_tracker->controller_tracker->set_input(action->action_name, Variant(value)); } break; case OpenXRAction::OPENXR_ACTION_VECTOR2: { Vector2 value = openxr_api->get_action_vector2(action->action_rid, p_tracker->tracker_rid); - p_tracker->positional_tracker->set_input(action->action_name, Variant(value)); + p_tracker->controller_tracker->set_input(action->action_name, Variant(value)); } break; case OpenXRAction::OPENXR_ACTION_POSE: { Transform3D transform; @@ -523,9 +526,9 @@ void OpenXRInterface::handle_tracker(Tracker *p_tracker) { XRPose::TrackingConfidence confidence = openxr_api->get_action_pose(action->action_rid, p_tracker->tracker_rid, transform, linear, angular); if (confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) { - p_tracker->positional_tracker->set_pose(action->action_name, transform, linear, angular, confidence); + p_tracker->controller_tracker->set_pose(action->action_name, transform, linear, angular, confidence); } else { - p_tracker->positional_tracker->invalidate_pose(action->action_name); + p_tracker->controller_tracker->invalidate_pose(action->action_name); } } break; default: { @@ -567,8 +570,8 @@ void OpenXRInterface::free_trackers() { Tracker *tracker = trackers[i]; openxr_api->tracker_free(tracker->tracker_rid); - xr_server->remove_tracker(tracker->positional_tracker); - tracker->positional_tracker.unref(); + xr_server->remove_tracker(tracker->controller_tracker); + tracker->controller_tracker.unref(); memdelete(tracker); } @@ -1005,7 +1008,7 @@ void OpenXRInterface::handle_hand_tracking(const String &p_path, OpenXRHandTrack OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); if (hand_tracking_ext && hand_tracking_ext->get_active()) { OpenXRInterface::Tracker *tracker = find_tracker(p_path); - if (tracker && tracker->positional_tracker.is_valid()) { + if (tracker && tracker->controller_tracker.is_valid()) { XrSpaceLocationFlags location_flags = hand_tracking_ext->get_hand_joint_location_flags(p_hand, XR_HAND_JOINT_PALM_EXT); if (location_flags & (XR_SPACE_LOCATION_ORIENTATION_VALID_BIT + XR_SPACE_LOCATION_POSITION_VALID_BIT)) { @@ -1035,9 +1038,9 @@ void OpenXRInterface::handle_hand_tracking(const String &p_path, OpenXRHandTrack angular_velocity = hand_tracking_ext->get_hand_joint_angular_velocity(p_hand, XR_HAND_JOINT_PALM_EXT); } - tracker->positional_tracker->set_pose("skeleton", transform, linear_velocity, angular_velocity, confidence); + tracker->controller_tracker->set_pose("skeleton", transform, linear_velocity, angular_velocity, confidence); } else { - tracker->positional_tracker->invalidate_pose("skeleton"); + tracker->controller_tracker->invalidate_pose("skeleton"); } } } diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index 737f22d6422..e916c7dac20 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -35,8 +35,8 @@ #include "extensions/openxr_hand_tracking_extension.h" #include "openxr_api.h" +#include "servers/xr/xr_controller_tracker.h" #include "servers/xr/xr_interface.h" -#include "servers/xr/xr_positional_tracker.h" // declare some default strings #define INTERACTION_PROFILE_NONE "/interaction_profiles/none" @@ -73,7 +73,7 @@ private: struct Tracker { // A tracker we've registered with OpenXR String tracker_name; // Name of our tracker (can be altered from the action map) Vector actions; // Actions related to this tracker - Ref positional_tracker; // Our positional tracker object that holds our tracker state + Ref controller_tracker; // Our positional tracker object that holds our tracker state RID tracker_rid; // RID of the tracker registered with our OpenXR API RID interaction_profile; // RID of the interaction profile bound to this tracker (can be null) }; diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml index caf7958f6bf..9fd4511d2bf 100644 --- a/modules/webxr/doc_classes/WebXRInterface.xml +++ b/modules/webxr/doc_classes/WebXRInterface.xml @@ -114,10 +114,10 @@ - + - Gets an [XRPositionalTracker] for the given [param input_source_id]. + Gets an [XRControllerTracker] for the given [param input_source_id]. In the context of WebXR, an input source can be an advanced VR controller like the Oculus Touch or Index controllers, or even a tap on the screen, a spoken voice command or a button press on the device itself. When a non-traditional input source is used, interpret the position and orientation of the [XRPositionalTracker] as a ray pointing at the object the user wishes to interact with. Use this method to get information about the input source that triggered one of these signals: - [signal selectstart] diff --git a/modules/webxr/webxr_interface.compat.inc b/modules/webxr/webxr_interface.compat.inc new file mode 100644 index 00000000000..97a9d44ca91 --- /dev/null +++ b/modules/webxr/webxr_interface.compat.inc @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* webxr_interface.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DISABLE_DEPRECATED + +Ref WebXRInterface::_get_input_source_tracker_bind_compat_90645(int p_input_source_id) const { + return get_input_source_tracker(p_input_source_id); +} + +void WebXRInterface::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("get_input_source_tracker", "input_source_id"), &WebXRInterface::_get_input_source_tracker_bind_compat_90645); +} + +#endif // DISABLE_DEPRECATED diff --git a/modules/webxr/webxr_interface.cpp b/modules/webxr/webxr_interface.cpp index c3efebef0f1..4795fcdcd6c 100644 --- a/modules/webxr/webxr_interface.cpp +++ b/modules/webxr/webxr_interface.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "webxr_interface.h" +#include "webxr_interface.compat.inc" #include diff --git a/modules/webxr/webxr_interface.h b/modules/webxr/webxr_interface.h index 06c18d0486e..241dc9fe76e 100644 --- a/modules/webxr/webxr_interface.h +++ b/modules/webxr/webxr_interface.h @@ -31,8 +31,8 @@ #ifndef WEBXR_INTERFACE_H #define WEBXR_INTERFACE_H +#include "servers/xr/xr_controller_tracker.h" #include "servers/xr/xr_interface.h" -#include "servers/xr/xr_positional_tracker.h" /** The WebXR interface is a VR/AR interface that can be used on the web. @@ -44,6 +44,11 @@ class WebXRInterface : public XRInterface { protected: static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + static void _bind_compatibility_methods(); + Ref _get_input_source_tracker_bind_compat_90645(int p_input_source_id) const; +#endif + public: enum TargetRayMode { TARGET_RAY_MODE_UNKNOWN, @@ -64,7 +69,7 @@ public: virtual String get_reference_space_type() const = 0; virtual String get_enabled_features() const = 0; virtual bool is_input_source_active(int p_input_source_id) const = 0; - virtual Ref get_input_source_tracker(int p_input_source_id) const = 0; + virtual Ref get_input_source_tracker(int p_input_source_id) const = 0; virtual TargetRayMode get_input_source_target_ray_mode(int p_input_source_id) const = 0; virtual String get_visibility_state() const = 0; virtual float get_display_refresh_rate() const = 0; diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index c6213d1aae1..535d464d6fc 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -164,8 +164,8 @@ bool WebXRInterfaceJS::is_input_source_active(int p_input_source_id) const { return input_sources[p_input_source_id].active; } -Ref WebXRInterfaceJS::get_input_source_tracker(int p_input_source_id) const { - ERR_FAIL_INDEX_V(p_input_source_id, input_source_count, Ref()); +Ref WebXRInterfaceJS::get_input_source_tracker(int p_input_source_id) const { + ERR_FAIL_INDEX_V(p_input_source_id, input_source_count, Ref()); return input_sources[p_input_source_id].tracker; } @@ -307,7 +307,7 @@ void WebXRInterfaceJS::uninitialize() { for (int i = 0; i < HAND_MAX; i++) { if (hand_trackers[i].is_valid()) { - xr_server->remove_hand_tracker(i == 0 ? "/user/left" : "/user/right"); + xr_server->remove_tracker(hand_trackers[i]); hand_trackers[i].unref(); } @@ -616,7 +616,7 @@ void WebXRInterfaceJS::_update_input_source(int p_input_source_id) { input_source.target_ray_mode = (WebXRInterface::TargetRayMode)tmp_target_ray_mode; input_source.touch_index = touch_index; - Ref &tracker = input_source.tracker; + Ref &tracker = input_source.tracker; if (tracker.is_null()) { tracker.instantiate(); @@ -630,7 +630,6 @@ void WebXRInterfaceJS::_update_input_source(int p_input_source_id) { // Input source id's 0 and 1 are always the left and right hands. if (p_input_source_id < 2) { - tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); tracker->set_tracker_name(tracker_name); tracker->set_tracker_desc(p_input_source_id == 0 ? "Left hand controller" : "Right hand controller"); tracker->set_tracker_hand(p_input_source_id == 0 ? XRPositionalTracker::TRACKER_HAND_LEFT : XRPositionalTracker::TRACKER_HAND_RIGHT); @@ -715,6 +714,7 @@ void WebXRInterfaceJS::_update_input_source(int p_input_source_id) { if (unlikely(hand_tracker.is_null())) { hand_tracker.instantiate(); hand_tracker->set_hand(p_input_source_id == 0 ? XRHandTracker::HAND_LEFT : XRHandTracker::HAND_RIGHT); + hand_tracker->set_tracker_name(p_input_source_id == 0 ? "/user/hand_tracker/left" : "/user/hand_tracker/right"); // These flags always apply, since WebXR doesn't give us enough insight to be more fine grained. BitField joint_flags(XRHandTracker::HAND_JOINT_FLAG_POSITION_VALID | XRHandTracker::HAND_JOINT_FLAG_ORIENTATION_VALID | XRHandTracker::HAND_JOINT_FLAG_POSITION_TRACKED | XRHandTracker::HAND_JOINT_FLAG_ORIENTATION_TRACKED); @@ -723,7 +723,7 @@ void WebXRInterfaceJS::_update_input_source(int p_input_source_id) { } hand_trackers[p_input_source_id] = hand_tracker; - xr_server->add_hand_tracker(p_input_source_id == 0 ? "/user/left" : "/user/right", hand_tracker); + xr_server->add_tracker(hand_tracker); } hand_tracker->set_has_tracking_data(true); @@ -746,10 +746,12 @@ void WebXRInterfaceJS::_update_input_source(int p_input_source_id) { Transform3D palm_transform; palm_transform.origin = (Vector3(start_pos[0], start_pos[1], start_pos[2]) + Vector3(end_pos[0], end_pos[1], end_pos[2])) / 2.0; hand_tracker->set_hand_joint_transform(XRHandTracker::HAND_JOINT_PALM, palm_transform); + hand_tracker->set_pose("default", palm_transform, Vector3(), Vector3()); } } else if (hand_tracker.is_valid()) { hand_tracker->set_has_tracking_data(false); + hand_tracker->invalidate_pose("default"); } } } diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h index fc5df3a59bf..afce28d410e 100644 --- a/modules/webxr/webxr_interface_js.h +++ b/modules/webxr/webxr_interface_js.h @@ -33,6 +33,8 @@ #ifdef WEB_ENABLED +#include "servers/xr/xr_controller_tracker.h" +#include "servers/xr/xr_hand_tracker.h" #include "webxr_interface.h" /** @@ -68,7 +70,7 @@ private: static constexpr uint8_t input_source_count = 16; struct InputSource { - Ref tracker; + Ref tracker; bool active = false; TargetRayMode target_ray_mode; int touch_index = -1; @@ -102,7 +104,7 @@ public: virtual String get_reference_space_type() const override; virtual String get_enabled_features() const override; virtual bool is_input_source_active(int p_input_source_id) const override; - virtual Ref get_input_source_tracker(int p_input_source_id) const override; + virtual Ref get_input_source_tracker(int p_input_source_id) const override; virtual TargetRayMode get_input_source_target_ray_mode(int p_input_source_id) const override; virtual String get_visibility_state() const override; virtual PackedVector3Array get_play_area() const override; diff --git a/scene/3d/xr_body_modifier_3d.cpp b/scene/3d/xr_body_modifier_3d.cpp index 0099784a05b..8aec3e856ee 100644 --- a/scene/3d/xr_body_modifier_3d.cpp +++ b/scene/3d/xr_body_modifier_3d.cpp @@ -44,13 +44,9 @@ void XRBodyModifier3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bone_update", "bone_update"), &XRBodyModifier3D::set_bone_update); ClassDB::bind_method(D_METHOD("get_bone_update"), &XRBodyModifier3D::get_bone_update); - ClassDB::bind_method(D_METHOD("set_show_when_tracked", "show"), &XRBodyModifier3D::set_show_when_tracked); - ClassDB::bind_method(D_METHOD("get_show_when_tracked"), &XRBodyModifier3D::get_show_when_tracked); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "body_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/body"), "set_body_tracker", "get_body_tracker"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "body_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/body_tracker"), "set_body_tracker", "get_body_tracker"); ADD_PROPERTY(PropertyInfo(Variant::INT, "body_update", PROPERTY_HINT_FLAGS, "Upper Body,Lower Body,Hands"), "set_body_update", "get_body_update"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_update", PROPERTY_HINT_ENUM, "Full,Rotation Only"), "set_bone_update", "get_bone_update"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_when_tracked"), "set_show_when_tracked", "get_show_when_tracked"); BIND_BITFIELD_FLAG(BODY_UPDATE_UPPER_BODY); BIND_BITFIELD_FLAG(BODY_UPDATE_LOWER_BODY); @@ -86,14 +82,6 @@ XRBodyModifier3D::BoneUpdate XRBodyModifier3D::get_bone_update() const { return bone_update; } -void XRBodyModifier3D::set_show_when_tracked(bool p_show_when_tracked) { - show_when_tracked = p_show_when_tracked; -} - -bool XRBodyModifier3D::get_show_when_tracked() const { - return show_when_tracked; -} - void XRBodyModifier3D::_get_joint_data() { // Table of Godot Humanoid bone names. static const String bone_names[XRBodyTracker::JOINT_MAX] = { @@ -189,7 +177,7 @@ void XRBodyModifier3D::_get_joint_data() { joints[i].parent_joint = -1; } - Skeleton3D *skeleton = get_skeleton(); + const Skeleton3D *skeleton = get_skeleton(); if (!skeleton) { return; } @@ -257,27 +245,22 @@ void XRBodyModifier3D::_process_modification() { return; } - XRServer *xr_server = XRServer::get_singleton(); + const XRServer *xr_server = XRServer::get_singleton(); if (!xr_server) { return; } - Ref tracker = xr_server->get_body_tracker(tracker_name); - if (tracker.is_null()) { + const Ref tracker = xr_server->get_tracker(tracker_name); + if (!tracker.is_valid()) { return; } - // Handle no tracking data. + // Skip if no tracking data. if (!tracker->get_has_tracking_data()) { - // If tracking-state determines visibility then hide the node. - if (show_when_tracked) { - set_visible(false); - } return; } // Get the world and skeleton scale. - const float ws = xr_server->get_world_scale(); const float ss = skeleton->get_motion_scale(); // Read the relevant tracking data. This applies the skeleton motion scale to @@ -296,12 +279,8 @@ void XRBodyModifier3D::_process_modification() { } } - // Handle root joint not tracked. + // Skip if root joint not tracked. if (!has_valid_data[XRBodyTracker::JOINT_ROOT]) { - // If tracking-state determines visibility then hide the node. - if (show_when_tracked) { - set_visible(false); - } return; } @@ -331,16 +310,6 @@ void XRBodyModifier3D::_process_modification() { // Always update the bone rotation. skeleton->set_bone_pose_rotation(joints[joint].bone, Quaternion(relative_transform.basis)); } - - // Transform to the tracking data root pose. This also applies the XR world-scale to allow - // scaling the avatars mesh and skeleton appropriately (if they are child nodes). - set_transform( - transforms[XRBodyTracker::JOINT_ROOT] * ws); - - // If tracking-state determines visibility then show the node. - if (show_when_tracked) { - set_visible(true); - } } void XRBodyModifier3D::_tracker_changed(const StringName &p_tracker_name, const Ref &p_tracker) { diff --git a/scene/3d/xr_body_modifier_3d.h b/scene/3d/xr_body_modifier_3d.h index 03b1c07d53d..9ff0cd7207c 100644 --- a/scene/3d/xr_body_modifier_3d.h +++ b/scene/3d/xr_body_modifier_3d.h @@ -66,9 +66,6 @@ public: void set_bone_update(BoneUpdate p_bone_update); BoneUpdate get_bone_update() const; - void set_show_when_tracked(bool p_show_when_tracked); - bool get_show_when_tracked() const; - void _notification(int p_what); protected: @@ -83,10 +80,9 @@ private: int parent_joint = -1; }; - StringName tracker_name = "/user/body"; + StringName tracker_name = "/user/body_tracker"; BitField body_update = BODY_UPDATE_UPPER_BODY | BODY_UPDATE_LOWER_BODY | BODY_UPDATE_HANDS; BoneUpdate bone_update = BONE_UPDATE_FULL; - bool show_when_tracked = true; JointData joints[XRBodyTracker::JOINT_MAX]; void _get_joint_data(); diff --git a/scene/3d/xr_face_modifier_3d.cpp b/scene/3d/xr_face_modifier_3d.cpp index be92a587b0d..43cef95fb9a 100644 --- a/scene/3d/xr_face_modifier_3d.cpp +++ b/scene/3d/xr_face_modifier_3d.cpp @@ -495,7 +495,7 @@ static void remove_driven_unified_blend_shapes(RBMap &p_blend_mapping) void XRFaceModifier3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_face_tracker", "tracker_name"), &XRFaceModifier3D::set_face_tracker); ClassDB::bind_method(D_METHOD("get_face_tracker"), &XRFaceModifier3D::get_face_tracker); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "face_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/head"), "set_face_tracker", "get_face_tracker"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "face_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/face_tracker"), "set_face_tracker", "get_face_tracker"); ClassDB::bind_method(D_METHOD("set_target", "target"), &XRFaceModifier3D::set_target); ClassDB::bind_method(D_METHOD("get_target"), &XRFaceModifier3D::get_target); @@ -576,8 +576,8 @@ void XRFaceModifier3D::_update_face_blends() const { } // Get the face tracker. - const Ref p = xr_server->get_face_tracker(tracker_name); - if (!p.is_valid()) { + const Ref tracker = xr_server->get_tracker(tracker_name); + if (!tracker.is_valid()) { return; } @@ -588,7 +588,7 @@ void XRFaceModifier3D::_update_face_blends() const { } // Get the blend weights. - const PackedFloat32Array weights = p->get_blend_shapes(); + const PackedFloat32Array weights = tracker->get_blend_shapes(); // Apply all the face blend weights to the mesh. for (const KeyValue &it : blend_mapping) { diff --git a/scene/3d/xr_face_modifier_3d.h b/scene/3d/xr_face_modifier_3d.h index 147c374e95e..e5e59afe1d6 100644 --- a/scene/3d/xr_face_modifier_3d.h +++ b/scene/3d/xr_face_modifier_3d.h @@ -47,7 +47,7 @@ class XRFaceModifier3D : public Node3D { GDCLASS(XRFaceModifier3D, Node3D); private: - StringName tracker_name = "/user/head"; + StringName tracker_name = "/user/face_tracker"; NodePath target; // Map from XRFaceTracker blend shape index to mesh blend shape index. diff --git a/scene/3d/xr_hand_modifier_3d.cpp b/scene/3d/xr_hand_modifier_3d.cpp index 7fecb530084..1e78a4630f5 100644 --- a/scene/3d/xr_hand_modifier_3d.cpp +++ b/scene/3d/xr_hand_modifier_3d.cpp @@ -40,7 +40,7 @@ void XRHandModifier3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bone_update", "bone_update"), &XRHandModifier3D::set_bone_update); ClassDB::bind_method(D_METHOD("get_bone_update"), &XRHandModifier3D::get_bone_update); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "hand_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/left,/user/right"), "set_hand_tracker", "get_hand_tracker"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "hand_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/hand_tracker/left,/user/hand_tracker/right"), "set_hand_tracker", "get_hand_tracker"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_update", PROPERTY_HINT_ENUM, "Full,Rotation Only"), "set_bone_update", "get_bone_update"); BIND_ENUM_CONSTANT(BONE_UPDATE_FULL); @@ -111,22 +111,30 @@ void XRHandModifier3D::_get_joint_data() { joints[i].parent_joint = -1; } - Skeleton3D *skeleton = get_skeleton(); + const Skeleton3D *skeleton = get_skeleton(); if (!skeleton) { return; } - XRServer *xr_server = XRServer::get_singleton(); + const XRServer *xr_server = XRServer::get_singleton(); if (!xr_server) { return; } - Ref tracker = xr_server->get_hand_tracker(tracker_name); + const Ref tracker = xr_server->get_tracker(tracker_name); if (tracker.is_null()) { return; } - XRHandTracker::Hand hand = tracker->get_hand(); + // Verify we have a left or right hand tracker. + const XRPositionalTracker::TrackerHand tracker_hand = tracker->get_tracker_hand(); + if (tracker_hand != XRPositionalTracker::TRACKER_HAND_LEFT && + tracker_hand != XRPositionalTracker::TRACKER_HAND_RIGHT) { + return; + } + + // Get the hand index (0 = left, 1 = right). + const int hand = tracker_hand == XRPositionalTracker::TRACKER_HAND_LEFT ? 0 : 1; // Find the skeleton-bones associated with each joint. int bones[XRHandTracker::HAND_JOINT_MAX]; @@ -176,18 +184,22 @@ void XRHandModifier3D::_process_modification() { return; } - XRServer *xr_server = XRServer::get_singleton(); + const XRServer *xr_server = XRServer::get_singleton(); if (!xr_server) { return; } - Ref tracker = xr_server->get_hand_tracker(tracker_name); + const Ref tracker = xr_server->get_tracker(tracker_name); if (tracker.is_null()) { return; } + // Skip if no tracking data + if (!tracker->get_has_tracking_data()) { + return; + } + // Get the world and skeleton scale. - const float ws = xr_server->get_world_scale(); const float ss = skeleton->get_motion_scale(); // We cache our transforms so we can quickly calculate local transforms. @@ -195,55 +207,44 @@ void XRHandModifier3D::_process_modification() { Transform3D transforms[XRHandTracker::HAND_JOINT_MAX]; Transform3D inv_transforms[XRHandTracker::HAND_JOINT_MAX]; - if (tracker->get_has_tracking_data()) { - for (int joint = 0; joint < XRHandTracker::HAND_JOINT_MAX; joint++) { - BitField flags = tracker->get_hand_joint_flags((XRHandTracker::HandJoint)joint); - has_valid_data[joint] = flags.has_flag(XRHandTracker::HAND_JOINT_FLAG_ORIENTATION_VALID); + for (int joint = 0; joint < XRHandTracker::HAND_JOINT_MAX; joint++) { + BitField flags = tracker->get_hand_joint_flags((XRHandTracker::HandJoint)joint); + has_valid_data[joint] = flags.has_flag(XRHandTracker::HAND_JOINT_FLAG_ORIENTATION_VALID); - if (has_valid_data[joint]) { - transforms[joint] = tracker->get_hand_joint_transform((XRHandTracker::HandJoint)joint); - transforms[joint].origin *= ss; - inv_transforms[joint] = transforms[joint].inverse(); - } + if (has_valid_data[joint]) { + transforms[joint] = tracker->get_hand_joint_transform((XRHandTracker::HandJoint)joint); + transforms[joint].origin *= ss; + inv_transforms[joint] = transforms[joint].inverse(); + } + } + + // Skip if palm has no tracking data + if (!has_valid_data[XRHandTracker::HAND_JOINT_PALM]) { + return; + } + + for (int joint = 0; joint < XRHandTracker::HAND_JOINT_MAX; joint++) { + // Get the skeleton bone (skip if none). + const int bone = joints[joint].bone; + if (bone == -1) { + continue; } - if (has_valid_data[XRHandTracker::HAND_JOINT_PALM]) { - for (int joint = 0; joint < XRHandTracker::HAND_JOINT_MAX; joint++) { - // Get the skeleton bone (skip if none). - const int bone = joints[joint].bone; - if (bone == -1) { - continue; - } + // Calculate the relative relationship to the parent bone joint. + const int parent_joint = joints[joint].parent_joint; + const Transform3D relative_transform = inv_transforms[parent_joint] * transforms[joint]; - // Calculate the relative relationship to the parent bone joint. - const int parent_joint = joints[joint].parent_joint; - const Transform3D relative_transform = inv_transforms[parent_joint] * transforms[joint]; - - // Update the bone position if enabled by update mode. - if (bone_update == BONE_UPDATE_FULL) { - skeleton->set_bone_pose_position(joints[joint].bone, relative_transform.origin); - } - - // Always update the bone rotation. - skeleton->set_bone_pose_rotation(joints[joint].bone, Quaternion(relative_transform.basis)); - } - - // Transform to the skeleton pose. This uses the HAND_JOINT_PALM position without skeleton-scaling, as it - // must be positioned to match the physical hand location. It is scaled with the world space to match - // the scaling done to the camera and eyes. - set_transform( - tracker->get_hand_joint_transform(XRHandTracker::HAND_JOINT_PALM) * ws); - - set_visible(true); - } else { - set_visible(false); + // Update the bone position if enabled by update mode. + if (bone_update == BONE_UPDATE_FULL) { + skeleton->set_bone_pose_position(joints[joint].bone, relative_transform.origin); } - } else { - set_visible(false); + + // Always update the bone rotation. + skeleton->set_bone_pose_rotation(joints[joint].bone, Quaternion(relative_transform.basis)); } } -void XRHandModifier3D::_tracker_changed(StringName p_tracker_name, const Ref &p_tracker) { +void XRHandModifier3D::_tracker_changed(StringName p_tracker_name, XRServer::TrackerType p_tracker_type) { if (tracker_name == p_tracker_name) { _get_joint_data(); } @@ -258,9 +259,9 @@ void XRHandModifier3D::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { XRServer *xr_server = XRServer::get_singleton(); if (xr_server) { - xr_server->connect("hand_tracker_added", callable_mp(this, &XRHandModifier3D::_tracker_changed)); - xr_server->connect("hand_tracker_updated", callable_mp(this, &XRHandModifier3D::_tracker_changed)); - xr_server->connect("hand_tracker_removed", callable_mp(this, &XRHandModifier3D::_tracker_changed).bind(Ref())); + xr_server->connect("tracker_added", callable_mp(this, &XRHandModifier3D::_tracker_changed)); + xr_server->connect("tracker_updated", callable_mp(this, &XRHandModifier3D::_tracker_changed)); + xr_server->connect("tracker_removed", callable_mp(this, &XRHandModifier3D::_tracker_changed)); } _get_joint_data(); @@ -268,9 +269,9 @@ void XRHandModifier3D::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { XRServer *xr_server = XRServer::get_singleton(); if (xr_server) { - xr_server->disconnect("hand_tracker_added", callable_mp(this, &XRHandModifier3D::_tracker_changed)); - xr_server->disconnect("hand_tracker_updated", callable_mp(this, &XRHandModifier3D::_tracker_changed)); - xr_server->disconnect("hand_tracker_removed", callable_mp(this, &XRHandModifier3D::_tracker_changed).bind(Ref())); + xr_server->disconnect("tracker_added", callable_mp(this, &XRHandModifier3D::_tracker_changed)); + xr_server->disconnect("tracker_updated", callable_mp(this, &XRHandModifier3D::_tracker_changed)); + xr_server->disconnect("tracker_removed", callable_mp(this, &XRHandModifier3D::_tracker_changed)); } for (int i = 0; i < XRHandTracker::HAND_JOINT_MAX; i++) { diff --git a/scene/3d/xr_hand_modifier_3d.h b/scene/3d/xr_hand_modifier_3d.h index 9f7ce45c9dd..67d1694d41a 100644 --- a/scene/3d/xr_hand_modifier_3d.h +++ b/scene/3d/xr_hand_modifier_3d.h @@ -69,12 +69,12 @@ private: int parent_joint = -1; }; - StringName tracker_name = "/user/left"; + StringName tracker_name = "/user/hand_tracker/left"; BoneUpdate bone_update = BONE_UPDATE_FULL; JointData joints[XRHandTracker::HAND_JOINT_MAX]; void _get_joint_data(); - void _tracker_changed(StringName p_tracker_name, const Ref &p_tracker); + void _tracker_changed(StringName p_tracker_name, XRServer::TrackerType p_tracker_type); }; VARIANT_ENUM_CAST(XRHandModifier3D::BoneUpdate) diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index 12a9f50ed7f..3f4b9626417 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -80,10 +80,11 @@ PackedStringArray XRCamera3D::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible() && is_inside_tree()) { - // must be child node of XROrigin3D! - XROrigin3D *origin = Object::cast_to(get_parent()); - if (origin == nullptr) { - warnings.push_back(RTR("XRCamera3D must have an XROrigin3D node as its parent.")); + // Warn if the node has a parent which isn't an XROrigin3D! + Node *parent = get_parent(); + XROrigin3D *origin = Object::cast_to(parent); + if (parent && origin == nullptr) { + warnings.push_back(RTR("XRCamera3D may not function as expected without an XROrigin3D node as its parent.")); }; } @@ -229,6 +230,10 @@ void XRNode3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_pose_name"), &XRNode3D::get_pose_name); ADD_PROPERTY(PropertyInfo(Variant::STRING, "pose", PROPERTY_HINT_ENUM_SUGGESTION), "set_pose_name", "get_pose_name"); + ClassDB::bind_method(D_METHOD("set_show_when_tracked", "show"), &XRNode3D::set_show_when_tracked); + ClassDB::bind_method(D_METHOD("get_show_when_tracked"), &XRNode3D::get_show_when_tracked); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_when_tracked"), "set_show_when_tracked", "get_show_when_tracked"); + ClassDB::bind_method(D_METHOD("get_is_active"), &XRNode3D::get_is_active); ClassDB::bind_method(D_METHOD("get_has_tracking_data"), &XRNode3D::get_has_tracking_data); ClassDB::bind_method(D_METHOD("get_pose"), &XRNode3D::get_pose); @@ -296,6 +301,14 @@ StringName XRNode3D::get_pose_name() const { return pose_name; } +void XRNode3D::set_show_when_tracked(bool p_show) { + show_when_tracked = p_show; +} + +bool XRNode3D::get_show_when_tracked() const { + return show_when_tracked; +} + bool XRNode3D::get_is_active() const { if (tracker.is_null()) { return false; @@ -402,6 +415,11 @@ void XRNode3D::_set_has_tracking_data(bool p_has_tracking_data) { // Handle change of has_tracking_data. has_tracking_data = p_has_tracking_data; emit_signal(SNAME("tracking_changed"), has_tracking_data); + + // If configured, show or hide the node based on tracking data. + if (show_when_tracked) { + set_visible(has_tracking_data); + } } XRNode3D::XRNode3D() { @@ -428,11 +446,12 @@ PackedStringArray XRNode3D::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible() && is_inside_tree()) { - // must be child node of XROrigin! - XROrigin3D *origin = Object::cast_to(get_parent()); - if (origin == nullptr) { - warnings.push_back(RTR("XRController3D must have an XROrigin3D node as its parent.")); - } + // Warn if the node has a parent which isn't an XROrigin3D! + Node *parent = get_parent(); + XROrigin3D *origin = Object::cast_to(parent); + if (parent && origin == nullptr) { + warnings.push_back(RTR("XRNode3D may not function as expected without an XROrigin3D node as its parent.")); + }; if (tracker_name == "") { warnings.push_back(RTR("No tracker name is set.")); diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index bdcccd51ea5..a42f6d470ff 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -79,6 +79,7 @@ private: StringName tracker_name; StringName pose_name = "default"; bool has_tracking_data = false; + bool show_when_tracked = false; protected: Ref tracker; @@ -105,6 +106,9 @@ public: bool get_is_active() const; bool get_has_tracking_data() const; + void set_show_when_tracked(bool p_show); + bool get_show_when_tracked() const; + void trigger_haptic_pulse(const String &p_action_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0); Ref get_pose(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 1c8833494d9..21682cca944 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -545,7 +545,7 @@ void register_scene_types() { GDREGISTER_CLASS(Camera3D); GDREGISTER_CLASS(AudioListener3D); GDREGISTER_CLASS(XRCamera3D); - GDREGISTER_ABSTRACT_CLASS(XRNode3D); + GDREGISTER_CLASS(XRNode3D); GDREGISTER_CLASS(XRController3D); GDREGISTER_CLASS(XRAnchor3D); GDREGISTER_CLASS(XROrigin3D); diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index c03c0b7a404..1a75614a4c0 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -94,6 +94,7 @@ #include "physics_server_3d_wrap_mt.h" #include "servers/extensions/physics_server_3d_extension.h" #include "xr/xr_body_tracker.h" +#include "xr/xr_controller_tracker.h" #include "xr/xr_face_tracker.h" #include "xr/xr_hand_tracker.h" #include "xr/xr_interface.h" @@ -325,12 +326,14 @@ void register_server_types() { GDREGISTER_ABSTRACT_CLASS(XRInterface); GDREGISTER_CLASS(XRBodyTracker); + GDREGISTER_CLASS(XRControllerTracker); GDREGISTER_CLASS(XRFaceTracker); GDREGISTER_CLASS(XRHandTracker); GDREGISTER_CLASS(XRInterfaceExtension); // can't register this as virtual because we need a creation function for our extensions. GDREGISTER_CLASS(XRPose); GDREGISTER_CLASS(XRPositionalTracker); GDREGISTER_CLASS(XRServer); + GDREGISTER_ABSTRACT_CLASS(XRTracker); #endif // _3D_DISABLED GDREGISTER_ABSTRACT_CLASS(NavigationServer3D); diff --git a/servers/xr/xr_body_tracker.cpp b/servers/xr/xr_body_tracker.cpp index cd58c14348e..9c82b809113 100644 --- a/servers/xr/xr_body_tracker.cpp +++ b/servers/xr/xr_body_tracker.cpp @@ -134,6 +134,14 @@ void XRBodyTracker::_bind_methods() { BIND_BITFIELD_FLAG(JOINT_FLAG_POSITION_TRACKED); } +void XRBodyTracker::set_tracker_type(XRServer::TrackerType p_type) { + ERR_FAIL_COND_MSG(p_type != XRServer::TRACKER_BODY, "XRBodyTracker must be of type TRACKER_BODY."); +} + +void XRBodyTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) { + ERR_FAIL_COND_MSG(p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN, "XRBodyTracker cannot specify hand."); +} + void XRBodyTracker::set_has_tracking_data(bool p_has_tracking_data) { has_tracking_data = p_has_tracking_data; } @@ -169,3 +177,7 @@ Transform3D XRBodyTracker::get_joint_transform(Joint p_joint) const { ERR_FAIL_INDEX_V(p_joint, JOINT_MAX, Transform3D()); return joint_transforms[p_joint]; } + +XRBodyTracker::XRBodyTracker() { + type = XRServer::TRACKER_BODY; +} diff --git a/servers/xr/xr_body_tracker.h b/servers/xr/xr_body_tracker.h index 659aa39df1b..544de8ca8bb 100644 --- a/servers/xr/xr_body_tracker.h +++ b/servers/xr/xr_body_tracker.h @@ -31,10 +31,10 @@ #ifndef XR_BODY_TRACKER_H #define XR_BODY_TRACKER_H -#include "core/object/ref_counted.h" +#include "servers/xr/xr_positional_tracker.h" -class XRBodyTracker : public RefCounted { - GDCLASS(XRBodyTracker, RefCounted); +class XRBodyTracker : public XRPositionalTracker { + GDCLASS(XRBodyTracker, XRPositionalTracker); _THREAD_SAFE_CLASS_ public: @@ -140,6 +140,9 @@ public: JOINT_FLAG_POSITION_TRACKED = 8, }; + void set_tracker_type(XRServer::TrackerType p_type) override; + void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) override; + void set_has_tracking_data(bool p_has_tracking_data); bool get_has_tracking_data() const; @@ -152,6 +155,8 @@ public: void set_joint_transform(Joint p_joint, const Transform3D &p_transform); Transform3D get_joint_transform(Joint p_joint) const; + XRBodyTracker(); + protected: static void _bind_methods(); diff --git a/servers/xr/xr_controller_tracker.cpp b/servers/xr/xr_controller_tracker.cpp new file mode 100644 index 00000000000..df85e86b7e9 --- /dev/null +++ b/servers/xr/xr_controller_tracker.cpp @@ -0,0 +1,39 @@ +/**************************************************************************/ +/* xr_controller_tracker.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "xr_controller_tracker.h" + +#include "core/input/input.h" + +void XRControllerTracker::_bind_methods(){}; + +XRControllerTracker::XRControllerTracker() { + type = XRServer::TRACKER_CONTROLLER; +} diff --git a/servers/xr/xr_controller_tracker.h b/servers/xr/xr_controller_tracker.h new file mode 100644 index 00000000000..a443cc1fd81 --- /dev/null +++ b/servers/xr/xr_controller_tracker.h @@ -0,0 +1,52 @@ +/**************************************************************************/ +/* xr_controller_tracker.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef XR_CONTROLLER_TRACKER_H +#define XR_CONTROLLER_TRACKER_H + +#include "core/os/thread_safe.h" +#include "servers/xr/xr_positional_tracker.h" + +/** + The controller tracker object as an object that represents the position and orientation of a controller. +*/ + +class XRControllerTracker : public XRPositionalTracker { + GDCLASS(XRControllerTracker, XRPositionalTracker); + _THREAD_SAFE_CLASS_ + +protected: + static void _bind_methods(); + +public: + XRControllerTracker(); +}; + +#endif // XR_CONTROLLER_TRACKER_H diff --git a/servers/xr/xr_face_tracker.cpp b/servers/xr/xr_face_tracker.cpp index a38ccfd527a..7015cd08055 100644 --- a/servers/xr/xr_face_tracker.cpp +++ b/servers/xr/xr_face_tracker.cpp @@ -187,6 +187,10 @@ void XRFaceTracker::_bind_methods() { ADD_PROPERTY_DEFAULT("blend_shapes", PackedFloat32Array()); // To prevent ludicrously large default values. } +void XRFaceTracker::set_tracker_type(XRServer::TrackerType p_type) { + ERR_FAIL_COND_MSG(p_type != XRServer::TRACKER_FACE, "XRFaceTracker must be of type TRACKER_FACE."); +} + float XRFaceTracker::get_blend_shape(BlendShapeEntry p_blend_shape) const { // Fail if the blend shape index is out of range. ERR_FAIL_INDEX_V(p_blend_shape, FT_MAX, 0.0f); @@ -220,3 +224,7 @@ void XRFaceTracker::set_blend_shapes(const PackedFloat32Array &p_blend_shapes) { // Copy the blend shape values into the blend shape array. memcpy(blend_shape_values, p_blend_shapes.ptr(), sizeof(blend_shape_values)); } + +XRFaceTracker::XRFaceTracker() { + type = XRServer::TRACKER_FACE; +} diff --git a/servers/xr/xr_face_tracker.h b/servers/xr/xr_face_tracker.h index b9f553cba69..a753a7abdc7 100644 --- a/servers/xr/xr_face_tracker.h +++ b/servers/xr/xr_face_tracker.h @@ -31,7 +31,7 @@ #ifndef XR_FACE_TRACKER_H #define XR_FACE_TRACKER_H -#include "core/object/ref_counted.h" +#include "servers/xr/xr_tracker.h" /** The XRFaceTracker class provides face blend shape weights. @@ -41,8 +41,8 @@ and Meta Movement standards. */ -class XRFaceTracker : public RefCounted { - GDCLASS(XRFaceTracker, RefCounted); +class XRFaceTracker : public XRTracker { + GDCLASS(XRFaceTracker, XRTracker); _THREAD_SAFE_CLASS_ public: @@ -195,12 +195,16 @@ public: FT_MAX // Maximum blend shape. }; + void set_tracker_type(XRServer::TrackerType p_type) override; + float get_blend_shape(BlendShapeEntry p_blend_shape) const; void set_blend_shape(BlendShapeEntry p_blend_shape, float p_value); PackedFloat32Array get_blend_shapes() const; void set_blend_shapes(const PackedFloat32Array &p_blend_shapes); + XRFaceTracker(); + protected: static void _bind_methods(); diff --git a/servers/xr/xr_hand_tracker.cpp b/servers/xr/xr_hand_tracker.cpp index 8cc2d5f7d28..cb0fbfb35f0 100644 --- a/servers/xr/xr_hand_tracker.cpp +++ b/servers/xr/xr_hand_tracker.cpp @@ -30,6 +30,8 @@ #include "xr_hand_tracker.h" +#include "xr_body_tracker.h" + void XRHandTracker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hand", "hand"), &XRHandTracker::set_hand); ClassDB::bind_method(D_METHOD("get_hand"), &XRHandTracker::get_hand); @@ -55,7 +57,6 @@ void XRHandTracker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hand_joint_angular_velocity", "joint", "angular_velocity"), &XRHandTracker::set_hand_joint_angular_velocity); ClassDB::bind_method(D_METHOD("get_hand_joint_angular_velocity", "joint"), &XRHandTracker::get_hand_joint_angular_velocity); - ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Left,Right"), "set_hand", "get_hand"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "has_tracking_data", PROPERTY_HINT_NONE), "set_has_tracking_data", "get_has_tracking_data"); ADD_PROPERTY(PropertyInfo(Variant::INT, "hand_tracking_source", PROPERTY_HINT_ENUM, "Unknown,Unobstructed,Controller"), "set_hand_tracking_source", "get_hand_tracking_source"); @@ -104,8 +105,49 @@ void XRHandTracker::_bind_methods() { BIND_BITFIELD_FLAG(HAND_JOINT_FLAG_ANGULAR_VELOCITY_VALID); } +void XRHandTracker::set_tracker_type(XRServer::TrackerType p_type) { + ERR_FAIL_COND_MSG(p_type != XRServer::TRACKER_HAND, "XRHandTracker must be of type TRACKER_HAND."); +} + +void XRHandTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) { + ERR_FAIL_INDEX(p_hand, TRACKER_HAND_MAX); + + switch (p_hand) { + case TRACKER_HAND_LEFT: + tracker_hand = TRACKER_HAND_LEFT; + hand = HAND_LEFT; + break; + + case TRACKER_HAND_RIGHT: + tracker_hand = TRACKER_HAND_RIGHT; + hand = HAND_RIGHT; + break; + + case TRACKER_HAND_UNKNOWN: + default: + ERR_FAIL_MSG("XRHandTracker must specify hand"); + break; + } +} + void XRHandTracker::set_hand(XRHandTracker::Hand p_hand) { - hand = p_hand; + ERR_FAIL_INDEX(p_hand, HAND_MAX); + + switch (p_hand) { + case HAND_LEFT: + tracker_hand = TRACKER_HAND_LEFT; + hand = HAND_LEFT; + break; + + case HAND_RIGHT: + tracker_hand = TRACKER_HAND_RIGHT; + hand = HAND_RIGHT; + break; + + default: + ERR_FAIL_MSG("XRHandTracker must specify hand"); + break; + } } XRHandTracker::Hand XRHandTracker::get_hand() const { @@ -177,3 +219,7 @@ Vector3 XRHandTracker::get_hand_joint_angular_velocity(XRHandTracker::HandJoint ERR_FAIL_INDEX_V(p_joint, HAND_JOINT_MAX, Vector3()); return hand_joint_angular_velocities[p_joint]; } + +XRHandTracker::XRHandTracker() { + type = XRServer::TRACKER_HAND; +} diff --git a/servers/xr/xr_hand_tracker.h b/servers/xr/xr_hand_tracker.h index 648f02d1f85..8ef3c229c31 100644 --- a/servers/xr/xr_hand_tracker.h +++ b/servers/xr/xr_hand_tracker.h @@ -31,10 +31,10 @@ #ifndef XR_HAND_TRACKER_H #define XR_HAND_TRACKER_H -#include "core/object/ref_counted.h" +#include "servers/xr/xr_positional_tracker.h" -class XRHandTracker : public RefCounted { - GDCLASS(XRHandTracker, RefCounted); +class XRHandTracker : public XRPositionalTracker { + GDCLASS(XRHandTracker, XRPositionalTracker); _THREAD_SAFE_CLASS_ public: @@ -90,6 +90,9 @@ public: HAND_JOINT_FLAG_ANGULAR_VELOCITY_VALID = 32, }; + void set_tracker_type(XRServer::TrackerType p_type) override; + void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) override; + void set_hand(Hand p_hand); Hand get_hand() const; @@ -114,6 +117,8 @@ public: void set_hand_joint_angular_velocity(HandJoint p_joint, const Vector3 &p_velocity); Vector3 get_hand_joint_angular_velocity(HandJoint p_joint) const; + XRHandTracker(); + protected: static void _bind_methods(); diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index 6c15e4c1b0f..b4792377307 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -31,23 +31,13 @@ #include "xr_positional_tracker.h" #include "core/input/input.h" +#include "xr_controller_tracker.h" void XRPositionalTracker::_bind_methods() { BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN); BIND_ENUM_CONSTANT(TRACKER_HAND_LEFT); BIND_ENUM_CONSTANT(TRACKER_HAND_RIGHT); - - ClassDB::bind_method(D_METHOD("get_tracker_type"), &XRPositionalTracker::get_tracker_type); - ClassDB::bind_method(D_METHOD("set_tracker_type", "type"), &XRPositionalTracker::set_tracker_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_tracker_type", "get_tracker_type"); - - ClassDB::bind_method(D_METHOD("get_tracker_name"), &XRPositionalTracker::get_tracker_name); - ClassDB::bind_method(D_METHOD("set_tracker_name", "name"), &XRPositionalTracker::set_tracker_name); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_tracker_name", "get_tracker_name"); - - ClassDB::bind_method(D_METHOD("get_tracker_desc"), &XRPositionalTracker::get_tracker_desc); - ClassDB::bind_method(D_METHOD("set_tracker_desc", "description"), &XRPositionalTracker::set_tracker_desc); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_tracker_desc", "get_tracker_desc"); + BIND_ENUM_CONSTANT(TRACKER_HAND_MAX); ClassDB::bind_method(D_METHOD("get_tracker_profile"), &XRPositionalTracker::get_tracker_profile); ClassDB::bind_method(D_METHOD("set_tracker_profile", "profile"), &XRPositionalTracker::set_tracker_profile); @@ -73,34 +63,6 @@ void XRPositionalTracker::_bind_methods() { ADD_SIGNAL(MethodInfo("profile_changed", PropertyInfo(Variant::STRING, "role"))); }; -void XRPositionalTracker::set_tracker_type(XRServer::TrackerType p_type) { - if (type != p_type) { - type = p_type; - hand = XRPositionalTracker::TRACKER_HAND_UNKNOWN; - }; -}; - -XRServer::TrackerType XRPositionalTracker::get_tracker_type() const { - return type; -}; - -void XRPositionalTracker::set_tracker_name(const StringName &p_name) { - // Note: this should not be changed after the tracker is registered with the XRServer! - name = p_name; -}; - -StringName XRPositionalTracker::get_tracker_name() const { - return name; -}; - -void XRPositionalTracker::set_tracker_desc(const String &p_desc) { - description = p_desc; -} - -String XRPositionalTracker::get_tracker_desc() const { - return description; -} - void XRPositionalTracker::set_tracker_profile(const String &p_profile) { if (profile != p_profile) { profile = p_profile; @@ -114,19 +76,12 @@ String XRPositionalTracker::get_tracker_profile() const { } XRPositionalTracker::TrackerHand XRPositionalTracker::get_tracker_hand() const { - return hand; + return tracker_hand; }; void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) { - XRServer *xr_server = XRServer::get_singleton(); - ERR_FAIL_NULL(xr_server); - - if (hand != p_hand) { - // we can only set this if we've previously set this to be a controller!! - ERR_FAIL_COND((type != XRServer::TRACKER_CONTROLLER) && (p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN)); - - hand = p_hand; - }; + ERR_FAIL_INDEX(p_hand, TRACKER_HAND_MAX); + tracker_hand = p_hand; }; bool XRPositionalTracker::has_pose(const StringName &p_action_name) const { @@ -177,6 +132,11 @@ void XRPositionalTracker::set_pose(const StringName &p_action_name, const Transf } Variant XRPositionalTracker::get_input(const StringName &p_action_name) const { + // Complain if this method is called on a XRPositionalTracker instance. + if (!dynamic_cast(this)) { + WARN_DEPRECATED_MSG(R"*(The "get_input()" method is deprecated, use "XRControllerTracker" instead.)*"); + } + if (inputs.has(p_action_name)) { return inputs[p_action_name]; } else { @@ -185,10 +145,13 @@ Variant XRPositionalTracker::get_input(const StringName &p_action_name) const { } void XRPositionalTracker::set_input(const StringName &p_action_name, const Variant &p_value) { - bool changed = false; + // Complain if this method is called on a XRPositionalTracker instance. + if (!dynamic_cast(this)) { + WARN_DEPRECATED_MSG(R"*(The "set_input()" method is deprecated, use "XRControllerTracker" instead.)*"); + } // XR inputs - + bool changed; if (inputs.has(p_action_name)) { changed = inputs[p_action_name] != p_value; } else { @@ -227,9 +190,3 @@ void XRPositionalTracker::set_input(const StringName &p_action_name, const Varia } } } - -XRPositionalTracker::XRPositionalTracker() { - type = XRServer::TRACKER_UNKNOWN; - name = "Unknown"; - hand = TRACKER_HAND_UNKNOWN; -}; diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index d8939b45824..9e4e4d1cc35 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -34,6 +34,7 @@ #include "core/os/thread_safe.h" #include "scene/resources/mesh.h" #include "servers/xr/xr_pose.h" +#include "servers/xr/xr_tracker.h" #include "servers/xr_server.h" /** @@ -42,41 +43,33 @@ This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking. */ -class XRPositionalTracker : public RefCounted { - GDCLASS(XRPositionalTracker, RefCounted); +class XRPositionalTracker : public XRTracker { + GDCLASS(XRPositionalTracker, XRTracker); _THREAD_SAFE_CLASS_ public: enum TrackerHand { TRACKER_HAND_UNKNOWN, /* unknown or not applicable */ TRACKER_HAND_LEFT, /* controller is the left hand controller */ - TRACKER_HAND_RIGHT /* controller is the right hand controller */ + TRACKER_HAND_RIGHT, /* controller is the right hand controller */ + TRACKER_HAND_MAX }; -private: - XRServer::TrackerType type; // type of tracker - StringName name; // (unique) name of the tracker - String description; // description of the tracker +protected: String profile; // this is interface dependent, for OpenXR this will be the interaction profile bound for to the tracker - TrackerHand hand; // if known, the hand this tracker is held in + TrackerHand tracker_hand = TRACKER_HAND_UNKNOWN; // if known, the hand this tracker is held in HashMap> poses; HashMap inputs; -protected: static void _bind_methods(); public: - void set_tracker_type(XRServer::TrackerType p_type); - XRServer::TrackerType get_tracker_type() const; - void set_tracker_name(const StringName &p_name); - StringName get_tracker_name() const; - void set_tracker_desc(const String &p_desc); - String get_tracker_desc() const; void set_tracker_profile(const String &p_profile); String get_tracker_profile() const; + XRPositionalTracker::TrackerHand get_tracker_hand() const; - void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand); + virtual void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand); bool has_pose(const StringName &p_action_name) const; Ref get_pose(const StringName &p_action_name) const; @@ -85,9 +78,6 @@ public: Variant get_input(const StringName &p_action_name) const; void set_input(const StringName &p_action_name, const Variant &p_value); - - XRPositionalTracker(); - ~XRPositionalTracker() {} }; VARIANT_ENUM_CAST(XRPositionalTracker::TrackerHand); diff --git a/servers/xr/xr_tracker.cpp b/servers/xr/xr_tracker.cpp new file mode 100644 index 00000000000..0b917a5dc3c --- /dev/null +++ b/servers/xr/xr_tracker.cpp @@ -0,0 +1,70 @@ +/**************************************************************************/ +/* xr_tracker.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "xr_tracker.h" + +void XRTracker::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_tracker_type"), &XRTracker::get_tracker_type); + ClassDB::bind_method(D_METHOD("set_tracker_type", "type"), &XRTracker::set_tracker_type); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_tracker_type", "get_tracker_type"); + + ClassDB::bind_method(D_METHOD("get_tracker_name"), &XRTracker::get_tracker_name); + ClassDB::bind_method(D_METHOD("set_tracker_name", "name"), &XRTracker::set_tracker_name); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_tracker_name", "get_tracker_name"); + + ClassDB::bind_method(D_METHOD("get_tracker_desc"), &XRTracker::get_tracker_desc); + ClassDB::bind_method(D_METHOD("set_tracker_desc", "description"), &XRTracker::set_tracker_desc); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_tracker_desc", "get_tracker_desc"); +}; + +void XRTracker::set_tracker_type(XRServer::TrackerType p_type) { + type = p_type; +}; + +XRServer::TrackerType XRTracker::get_tracker_type() const { + return type; +}; + +void XRTracker::set_tracker_name(const StringName &p_name) { + // Note: this should not be changed after the tracker is registered with the XRServer! + name = p_name; +}; + +StringName XRTracker::get_tracker_name() const { + return name; +}; + +void XRTracker::set_tracker_desc(const String &p_desc) { + description = p_desc; +} + +String XRTracker::get_tracker_desc() const { + return description; +} diff --git a/servers/xr/xr_tracker.h b/servers/xr/xr_tracker.h new file mode 100644 index 00000000000..3348e164d89 --- /dev/null +++ b/servers/xr/xr_tracker.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* xr_tracker.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef XR_TRACKER_H +#define XR_TRACKER_H + +#include "core/os/thread_safe.h" +#include "servers/xr_server.h" + +/** + The XR tracker object is a common base for all different types of XR trackers. +*/ + +class XRTracker : public RefCounted { + GDCLASS(XRTracker, RefCounted); + _THREAD_SAFE_CLASS_ + +protected: + XRServer::TrackerType type = XRServer::TRACKER_UNKNOWN; // type of tracker + StringName name = "Unknown"; // (unique) name of the tracker + String description; // description of the tracker + + static void _bind_methods(); + +public: + virtual void set_tracker_type(XRServer::TrackerType p_type); + XRServer::TrackerType get_tracker_type() const; + void set_tracker_name(const StringName &p_name); + StringName get_tracker_name() const; + void set_tracker_desc(const String &p_desc); + String get_tracker_desc() const; +}; + +#endif // XR_TRACKER_H diff --git a/servers/xr_server.compat.inc b/servers/xr_server.compat.inc new file mode 100644 index 00000000000..967666fa6fe --- /dev/null +++ b/servers/xr_server.compat.inc @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* xr_server.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DISABLE_DEPRECATED + +void XRServer::_add_tracker_bind_compat_90645(const Ref &p_tracker) { + add_tracker(p_tracker); +} + +void XRServer::_remove_tracker_bind_compat_90645(const Ref &p_tracker) { + remove_tracker(p_tracker); +} + +Ref XRServer::_get_tracker_bind_compat_90645(const StringName &p_name) const { + return get_tracker(p_name); +} + +void XRServer::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("add_tracker", "tracker"), &XRServer::_add_tracker_bind_compat_90645); + ClassDB::bind_compatibility_method(D_METHOD("remove_tracker", "tracker"), &XRServer::_remove_tracker_bind_compat_90645); + ClassDB::bind_compatibility_method(D_METHOD("get_tracker", "name"), &XRServer::_get_tracker_bind_compat_90645); +} + +#endif // DISABLE_DEPRECATED diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index af14ba4a00b..f1105a650d0 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -35,6 +35,7 @@ #include "xr/xr_hand_tracker.h" #include "xr/xr_interface.h" #include "xr/xr_positional_tracker.h" +#include "xr_server.compat.inc" XRServer::XRMode XRServer::xr_mode = XRMODE_DEFAULT; @@ -77,21 +78,6 @@ void XRServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_trackers", "tracker_types"), &XRServer::get_trackers); ClassDB::bind_method(D_METHOD("get_tracker", "tracker_name"), &XRServer::get_tracker); - ClassDB::bind_method(D_METHOD("add_hand_tracker", "tracker_name", "hand_tracker"), &XRServer::add_hand_tracker); - ClassDB::bind_method(D_METHOD("remove_hand_tracker", "tracker_name"), &XRServer::remove_hand_tracker); - ClassDB::bind_method(D_METHOD("get_hand_trackers"), &XRServer::get_hand_trackers); - ClassDB::bind_method(D_METHOD("get_hand_tracker", "tracker_name"), &XRServer::get_hand_tracker); - - ClassDB::bind_method(D_METHOD("add_face_tracker", "tracker_name", "face_tracker"), &XRServer::add_face_tracker); - ClassDB::bind_method(D_METHOD("remove_face_tracker", "tracker_name"), &XRServer::remove_face_tracker); - ClassDB::bind_method(D_METHOD("get_face_trackers"), &XRServer::get_face_trackers); - ClassDB::bind_method(D_METHOD("get_face_tracker", "tracker_name"), &XRServer::get_face_tracker); - - ClassDB::bind_method(D_METHOD("add_body_tracker", "tracker_name", "body_tracker"), &XRServer::add_body_tracker); - ClassDB::bind_method(D_METHOD("remove_body_tracker", "tracker_name"), &XRServer::remove_body_tracker); - ClassDB::bind_method(D_METHOD("get_body_trackers"), &XRServer::get_body_trackers); - ClassDB::bind_method(D_METHOD("get_body_tracker", "tracker_name"), &XRServer::get_body_tracker); - ClassDB::bind_method(D_METHOD("get_primary_interface"), &XRServer::get_primary_interface); ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_primary_interface); @@ -101,6 +87,9 @@ void XRServer::_bind_methods() { BIND_ENUM_CONSTANT(TRACKER_CONTROLLER); BIND_ENUM_CONSTANT(TRACKER_BASESTATION); BIND_ENUM_CONSTANT(TRACKER_ANCHOR); + BIND_ENUM_CONSTANT(TRACKER_HAND); + BIND_ENUM_CONSTANT(TRACKER_BODY); + BIND_ENUM_CONSTANT(TRACKER_FACE); BIND_ENUM_CONSTANT(TRACKER_ANY_KNOWN); BIND_ENUM_CONSTANT(TRACKER_UNKNOWN); BIND_ENUM_CONSTANT(TRACKER_ANY); @@ -115,18 +104,6 @@ void XRServer::_bind_methods() { ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"))); ADD_SIGNAL(MethodInfo("tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"))); ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"))); - - ADD_SIGNAL(MethodInfo("hand_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "hand_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRHandTracker"))); - ADD_SIGNAL(MethodInfo("hand_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "hand_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRHandTracker"))); - ADD_SIGNAL(MethodInfo("hand_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); - - ADD_SIGNAL(MethodInfo("face_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "face_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRFaceTracker"))); - ADD_SIGNAL(MethodInfo("face_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "face_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRFaceTracker"))); - ADD_SIGNAL(MethodInfo("face_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); - - ADD_SIGNAL(MethodInfo("body_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "body_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRBodyTracker"))); - ADD_SIGNAL(MethodInfo("body_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "body_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRBodyTracker"))); - ADD_SIGNAL(MethodInfo("body_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); }; double XRServer::get_world_scale() const { @@ -281,7 +258,7 @@ void XRServer::set_primary_interface(const Ref &p_primary_interface } }; -void XRServer::add_tracker(Ref p_tracker) { +void XRServer::add_tracker(const Ref &p_tracker) { ERR_FAIL_COND(p_tracker.is_null()); StringName tracker_name = p_tracker->get_tracker_name(); @@ -297,7 +274,7 @@ void XRServer::add_tracker(Ref p_tracker) { } }; -void XRServer::remove_tracker(Ref p_tracker) { +void XRServer::remove_tracker(const Ref &p_tracker) { ERR_FAIL_COND(p_tracker.is_null()); StringName tracker_name = p_tracker->get_tracker_name(); @@ -323,12 +300,12 @@ Dictionary XRServer::get_trackers(int p_tracker_types) { return res; } -Ref XRServer::get_tracker(const StringName &p_name) const { +Ref XRServer::get_tracker(const StringName &p_name) const { if (trackers.has(p_name)) { return trackers[p_name]; } else { // tracker hasn't been registered yet, which is fine, no need to spam the error log... - return Ref(); + return Ref(); } }; @@ -382,120 +359,6 @@ PackedStringArray XRServer::get_suggested_pose_names(const StringName &p_tracker return arr; } -void XRServer::add_hand_tracker(const StringName &p_tracker_name, Ref p_hand_tracker) { - ERR_FAIL_COND(p_hand_tracker.is_null()); - - if (!hand_trackers.has(p_tracker_name)) { - // We don't have a tracker with this name, we're going to add it. - hand_trackers[p_tracker_name] = p_hand_tracker; - emit_signal(SNAME("hand_tracker_added"), p_tracker_name, p_hand_tracker); - } else if (hand_trackers[p_tracker_name] != p_hand_tracker) { - // We already have a tracker with this name, we're going to replace it. - hand_trackers[p_tracker_name] = p_hand_tracker; - emit_signal(SNAME("hand_tracker_updated"), p_tracker_name, p_hand_tracker); - } -} - -void XRServer::remove_hand_tracker(const StringName &p_tracker_name) { - // Skip if no hand tracker is found. - if (!hand_trackers.has(p_tracker_name)) { - return; - } - - // Send the removed signal, then remove the hand tracker. - emit_signal(SNAME("hand_tracker_removed"), p_tracker_name); - hand_trackers.erase(p_tracker_name); -} - -Dictionary XRServer::get_hand_trackers() const { - return hand_trackers; -} - -Ref XRServer::get_hand_tracker(const StringName &p_tracker_name) const { - // Skip if no tracker is found. - if (!hand_trackers.has(p_tracker_name)) { - return Ref(); - } - - return hand_trackers[p_tracker_name]; -} - -void XRServer::add_face_tracker(const StringName &p_tracker_name, Ref p_face_tracker) { - ERR_FAIL_COND(p_face_tracker.is_null()); - - if (!face_trackers.has(p_tracker_name)) { - // We don't have a tracker with this name, we're going to add it. - face_trackers[p_tracker_name] = p_face_tracker; - emit_signal(SNAME("face_tracker_added"), p_tracker_name, p_face_tracker); - } else if (face_trackers[p_tracker_name] != p_face_tracker) { - // We already have a tracker with this name, we're going to replace it. - face_trackers[p_tracker_name] = p_face_tracker; - emit_signal(SNAME("face_tracker_updated"), p_tracker_name, p_face_tracker); - } -} - -void XRServer::remove_face_tracker(const StringName &p_tracker_name) { - // Skip if no face tracker is found. - if (!face_trackers.has(p_tracker_name)) { - return; - } - - // Send the removed signal, then remove the face tracker. - emit_signal(SNAME("face_tracker_removed"), p_tracker_name); - face_trackers.erase(p_tracker_name); -} - -Dictionary XRServer::get_face_trackers() const { - return face_trackers; -} - -Ref XRServer::get_face_tracker(const StringName &p_tracker_name) const { - // Skip if no tracker is found. - if (!face_trackers.has(p_tracker_name)) { - return Ref(); - } - - return face_trackers[p_tracker_name]; -} - -void XRServer::add_body_tracker(const StringName &p_tracker_name, Ref p_body_tracker) { - ERR_FAIL_COND(p_body_tracker.is_null()); - - if (!body_trackers.has(p_tracker_name)) { - // We don't have a tracker with this name, we're going to add it. - body_trackers[p_tracker_name] = p_body_tracker; - emit_signal(SNAME("body_tracker_added"), p_tracker_name, p_body_tracker); - } else if (body_trackers[p_tracker_name] != p_body_tracker) { - // We already have a tracker with this name, we're going to replace it. - body_trackers[p_tracker_name] = p_body_tracker; - emit_signal(SNAME("body_tracker_updated"), p_tracker_name, p_body_tracker); - } -} - -void XRServer::remove_body_tracker(const StringName &p_tracker_name) { - // Skip if no face tracker is found. - if (!body_trackers.has(p_tracker_name)) { - return; - } - - // Send the removed signal, then remove the face tracker. - emit_signal(SNAME("body_tracker_removed"), p_tracker_name); - body_trackers.erase(p_tracker_name); -} - -Dictionary XRServer::get_body_trackers() const { - return body_trackers; -} - -Ref XRServer::get_body_tracker(const StringName &p_tracker_name) const { - // Skip if no tracker is found. - if (!body_trackers.has(p_tracker_name)) { - return Ref(); - } - - return body_trackers[p_tracker_name]; -} - void XRServer::_process() { // called from our main game loop before we handle physics and game logic // note that we can have multiple interfaces active if we have interfaces that purely handle tracking @@ -545,14 +408,8 @@ XRServer::XRServer() { XRServer::~XRServer() { primary_interface.unref(); - while (interfaces.size() > 0) { - interfaces.remove_at(0); - } - - // TODO pretty sure there is a clear function or something... - while (trackers.size() > 0) { - trackers.erase(trackers.get_key_at_index(0)); - } + interfaces.clear(); + trackers.clear(); singleton = nullptr; }; diff --git a/servers/xr_server.h b/servers/xr_server.h index 6aaa34b21dc..717728171aa 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -38,10 +38,8 @@ #include "core/variant/variant.h" class XRInterface; +class XRTracker; class XRPositionalTracker; -class XRHandTracker; -class XRFaceTracker; -class XRBodyTracker; /** The XR server is a singleton object that gives access to the various @@ -71,6 +69,9 @@ public: TRACKER_CONTROLLER = 0x02, /* tracks a controller */ TRACKER_BASESTATION = 0x04, /* tracks location of a base station */ TRACKER_ANCHOR = 0x08, /* tracks an anchor point, used in AR to track a real live location */ + TRACKER_HAND = 0x10, /* tracks a hand */ + TRACKER_BODY = 0x20, /* tracks a body */ + TRACKER_FACE = 0x40, /* tracks a face */ TRACKER_UNKNOWN = 0x80, /* unknown tracker */ TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */ @@ -88,9 +89,6 @@ private: Vector> interfaces; Dictionary trackers; - Dictionary hand_trackers; - Dictionary face_trackers; - Dictionary body_trackers; Ref primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ @@ -103,6 +101,13 @@ protected: static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + static void _bind_compatibility_methods(); + void _add_tracker_bind_compat_90645(const Ref &p_tracker); + void _remove_tracker_bind_compat_90645(const Ref &p_tracker); + Ref _get_tracker_bind_compat_90645(const StringName &p_name) const; +#endif + public: static XRMode get_xr_mode(); static void set_xr_mode(XRMode p_mode); @@ -174,13 +179,13 @@ public: void set_primary_interface(const Ref &p_primary_interface); /* - Our trackers are objects that expose the orientation and position of physical devices such as controller, anchor points, etc. + Our trackers are objects that expose tracked information about physical objects such as controller, anchor points, faces, hands etc. They are created and managed by our active AR/VR interfaces. */ - void add_tracker(Ref p_tracker); - void remove_tracker(Ref p_tracker); + void add_tracker(const Ref &p_tracker); + void remove_tracker(const Ref &p_tracker); Dictionary get_trackers(int p_tracker_types); - Ref get_tracker(const StringName &p_name) const; + Ref get_tracker(const StringName &p_name) const; /* We don't know which trackers and actions will existing during runtime but we can request suggested names from our interfaces to help our IDE UI. @@ -189,30 +194,6 @@ public: PackedStringArray get_suggested_pose_names(const StringName &p_tracker_name) const; // Q: Should we add get_suggested_input_names and get_suggested_haptic_names even though we don't use them for the IDE? - /* - Hand trackers are objects that expose the tracked joints of a hand. - */ - void add_hand_tracker(const StringName &p_tracker_name, Ref p_hand_tracker); - void remove_hand_tracker(const StringName &p_tracker_name); - Dictionary get_hand_trackers() const; - Ref get_hand_tracker(const StringName &p_tracker_name) const; - - /* - Face trackers are objects that expose the tracked blend shapes of a face. - */ - void add_face_tracker(const StringName &p_tracker_name, Ref p_face_tracker); - void remove_face_tracker(const StringName &p_tracker_name); - Dictionary get_face_trackers() const; - Ref get_face_tracker(const StringName &p_tracker_name) const; - - /* - Body trackers are objects that expose the tracked joints of a body. - */ - void add_body_tracker(const StringName &p_tracker_name, Ref p_face_tracker); - void remove_body_tracker(const StringName &p_tracker_name); - Dictionary get_body_trackers() const; - Ref get_body_tracker(const StringName &p_tracker_name) const; - // Process is called before we handle our physics process and game process. This is where our interfaces will update controller data and such. void _process();