Rework XR Trackers to have a common ancestor. Allow creation of XRNode3D to drive node positions and visibility.

This commit is contained in:
Malcolm Nixon 2024-04-13 17:26:46 -04:00
parent 3b1806182a
commit 823ae7b3fa
49 changed files with 769 additions and 636 deletions

View File

@ -4,15 +4,15 @@
A node for driving body meshes from [XRBodyTracker] data. A node for driving body meshes from [XRBodyTracker] data.
</brief_description> </brief_description>
<description> <description>
This node uses body tracking data from a [XRBodyTracker] to animate the skeleton of a body mesh. This node uses body tracking data from an [XRBodyTracker] to pose 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. 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. 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.
</description> </description>
<tutorials> <tutorials>
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link> <link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
</tutorials> </tutorials>
<members> <members>
<member name="body_tracker" type="StringName" setter="set_body_tracker" getter="get_body_tracker" default="&amp;&quot;/user/body&quot;"> <member name="body_tracker" type="StringName" setter="set_body_tracker" getter="get_body_tracker" default="&amp;&quot;/user/body_tracker&quot;">
The name of the [XRBodyTracker] registered with [XRServer] to obtain the body tracking data from. The name of the [XRBodyTracker] registered with [XRServer] to obtain the body tracking data from.
</member> </member>
<member name="body_update" type="int" setter="set_body_update" getter="get_body_update" enum="XRBodyModifier3D.BodyUpdate" is_bitfield="true" default="7"> <member name="body_update" type="int" setter="set_body_update" getter="get_body_update" enum="XRBodyModifier3D.BodyUpdate" is_bitfield="true" default="7">
@ -21,9 +21,6 @@
<member name="bone_update" type="int" setter="set_bone_update" getter="get_bone_update" enum="XRBodyModifier3D.BoneUpdate" default="0"> <member name="bone_update" type="int" setter="set_bone_update" getter="get_bone_update" enum="XRBodyModifier3D.BoneUpdate" default="0">
Specifies the type of updates to perform on the bones. Specifies the type of updates to perform on the bones.
</member> </member>
<member name="show_when_tracked" type="bool" setter="set_show_when_tracked" getter="get_show_when_tracked" default="true">
If true then the nodes visibility is determined by whether tracking data is available.
</member>
</members> </members>
<constants> <constants>
<constant name="BODY_UPDATE_UPPER_BODY" value="1" enum="BodyUpdate" is_bitfield="true"> <constant name="BODY_UPDATE_UPPER_BODY" value="1" enum="BodyUpdate" is_bitfield="true">

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="XRBodyTracker" inherits="RefCounted" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <class name="XRBodyTracker" inherits="XRPositionalTracker" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description> <brief_description>
A tracked body in XR. A tracked body in XR.
</brief_description> </brief_description>
@ -49,6 +49,7 @@
<member name="has_tracking_data" type="bool" setter="set_has_tracking_data" getter="get_has_tracking_data" default="false"> <member name="has_tracking_data" type="bool" setter="set_has_tracking_data" getter="get_has_tracking_data" default="false">
If [code]true[/code], the body tracking data is valid. If [code]true[/code], the body tracking data is valid.
</member> </member>
<member name="type" type="int" setter="set_tracker_type" getter="get_tracker_type" overrides="XRTracker" enum="XRServer.TrackerType" default="32" />
</members> </members>
<constants> <constants>
<constant name="BODY_FLAG_UPPER_BODY_SUPPORTED" value="1" enum="BodyFlags" is_bitfield="true"> <constant name="BODY_FLAG_UPPER_BODY_SUPPORTED" value="1" enum="BodyFlags" is_bitfield="true">

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="XRControllerTracker" inherits="XRPositionalTracker" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A tracked controller.
</brief_description>
<description>
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.
</description>
<tutorials>
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
</tutorials>
<members>
<member name="type" type="int" setter="set_tracker_type" getter="get_tracker_type" overrides="XRTracker" enum="XRServer.TrackerType" default="2" />
</members>
</class>

View File

@ -12,7 +12,7 @@
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link> <link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
</tutorials> </tutorials>
<members> <members>
<member name="face_tracker" type="StringName" setter="set_face_tracker" getter="get_face_tracker" default="&amp;&quot;/user/head&quot;"> <member name="face_tracker" type="StringName" setter="set_face_tracker" getter="get_face_tracker" default="&amp;&quot;/user/face_tracker&quot;">
The [XRFaceTracker] path. The [XRFaceTracker] path.
</member> </member>
<member name="target" type="NodePath" setter="set_target" getter="get_target" default="NodePath(&quot;&quot;)"> <member name="target" type="NodePath" setter="set_target" getter="get_target" default="NodePath(&quot;&quot;)">

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="XRFaceTracker" inherits="RefCounted" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <class name="XRFaceTracker" inherits="XRTracker" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description> <brief_description>
A tracked face. A tracked face.
</brief_description> </brief_description>
@ -31,6 +31,7 @@
<member name="blend_shapes" type="PackedFloat32Array" setter="set_blend_shapes" getter="get_blend_shapes" default="PackedFloat32Array()"> <member name="blend_shapes" type="PackedFloat32Array" setter="set_blend_shapes" getter="get_blend_shapes" default="PackedFloat32Array()">
The array of face blend shape weights with indices corresponding to the [enum BlendShapeEntry] enum. The array of face blend shape weights with indices corresponding to the [enum BlendShapeEntry] enum.
</member> </member>
<member name="type" type="int" setter="set_tracker_type" getter="get_tracker_type" overrides="XRTracker" enum="XRServer.TrackerType" default="64" />
</members> </members>
<constants> <constants>
<constant name="FT_EYE_LOOK_OUT_RIGHT" value="0" enum="BlendShapeEntry"> <constant name="FT_EYE_LOOK_OUT_RIGHT" value="0" enum="BlendShapeEntry">

View File

@ -4,8 +4,8 @@
A node for driving hand meshes from [XRHandTracker] data. A node for driving hand meshes from [XRHandTracker] data.
</brief_description> </brief_description>
<description> <description>
This node uses hand tracking data from a [XRHandTracker] to animate the skeleton of a hand mesh. This node uses hand tracking data from an [XRHandTracker] to pose 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. 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. 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.
</description> </description>
<tutorials> <tutorials>
@ -15,7 +15,7 @@
<member name="bone_update" type="int" setter="set_bone_update" getter="get_bone_update" enum="XRHandModifier3D.BoneUpdate" default="0"> <member name="bone_update" type="int" setter="set_bone_update" getter="get_bone_update" enum="XRHandModifier3D.BoneUpdate" default="0">
Specifies the type of updates to perform on the bones. Specifies the type of updates to perform on the bones.
</member> </member>
<member name="hand_tracker" type="StringName" setter="set_hand_tracker" getter="get_hand_tracker" default="&amp;&quot;/user/left&quot;"> <member name="hand_tracker" type="StringName" setter="set_hand_tracker" getter="get_hand_tracker" default="&amp;&quot;/user/hand_tracker/left&quot;">
The name of the [XRHandTracker] registered with [XRServer] to obtain the hand tracking data from. The name of the [XRHandTracker] registered with [XRServer] to obtain the hand tracking data from.
</member> </member>
</members> </members>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="XRHandTracker" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <class name="XRHandTracker" inherits="XRPositionalTracker" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description> <brief_description>
A tracked hand in XR. A tracked hand in XR.
</brief_description> </brief_description>
@ -11,6 +11,12 @@
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link> <link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
</tutorials> </tutorials>
<methods> <methods>
<method name="get_hand" qualifiers="const">
<return type="int" enum="XRHandTracker.Hand" />
<description>
Returns the type of hand.
</description>
</method>
<method name="get_hand_joint_angular_velocity" qualifiers="const"> <method name="get_hand_joint_angular_velocity" qualifiers="const">
<return type="Vector3" /> <return type="Vector3" />
<param index="0" name="joint" type="int" enum="XRHandTracker.HandJoint" /> <param index="0" name="joint" type="int" enum="XRHandTracker.HandJoint" />
@ -46,6 +52,13 @@
Returns the transform for the given hand joint. Returns the transform for the given hand joint.
</description> </description>
</method> </method>
<method name="set_hand">
<return type="void" />
<param index="0" name="hand" type="int" enum="XRHandTracker.Hand" />
<description>
Sets the type of hand.
</description>
</method>
<method name="set_hand_joint_angular_velocity"> <method name="set_hand_joint_angular_velocity">
<return type="void" /> <return type="void" />
<param index="0" name="joint" type="int" enum="XRHandTracker.HandJoint" /> <param index="0" name="joint" type="int" enum="XRHandTracker.HandJoint" />
@ -88,15 +101,13 @@
</method> </method>
</methods> </methods>
<members> <members>
<member name="hand" type="int" setter="set_hand" getter="get_hand" enum="XRHandTracker.Hand" default="0">
The type of hand.
</member>
<member name="hand_tracking_source" type="int" setter="set_hand_tracking_source" getter="get_hand_tracking_source" enum="XRHandTracker.HandTrackingSource" default="0"> <member name="hand_tracking_source" type="int" setter="set_hand_tracking_source" getter="get_hand_tracking_source" enum="XRHandTracker.HandTrackingSource" default="0">
The source of the hand tracking data. The source of the hand tracking data.
</member> </member>
<member name="has_tracking_data" type="bool" setter="set_has_tracking_data" getter="get_has_tracking_data" default="false"> <member name="has_tracking_data" type="bool" setter="set_has_tracking_data" getter="get_has_tracking_data" default="false">
If [code]true[/code], the hand tracking data is valid. If [code]true[/code], the hand tracking data is valid.
</member> </member>
<member name="type" type="int" setter="set_tracker_type" getter="get_tracker_type" overrides="XRTracker" enum="XRServer.TrackerType" default="16" />
</members> </members>
<constants> <constants>
<constant name="HAND_LEFT" value="0" enum="Hand"> <constant name="HAND_LEFT" value="0" enum="Hand">

View File

@ -46,6 +46,9 @@
The name of the pose we're bound to. Which poses a tracker supports is not known during design time. 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]. 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].
</member> </member>
<member name="show_when_tracked" type="bool" setter="set_show_when_tracked" getter="get_show_when_tracked" default="false">
Enables showing the node when tracking starts, and hiding the node when tracking is lost.
</member>
<member name="tracker" type="StringName" setter="set_tracker" getter="get_tracker" default="&amp;&quot;&quot;"> <member name="tracker" type="StringName" setter="set_tracker" getter="get_tracker" default="&amp;&quot;&quot;">
The name of the tracker we're bound to. Which trackers are available is not known during design time. 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]. 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].

View File

@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="XRPositionalTracker" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <class name="XRPositionalTracker" inherits="XRTracker" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description> <brief_description>
A tracked object. A tracked object.
</brief_description> </brief_description>
<description> <description>
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. 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]. 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.
</description> </description>
<tutorials> <tutorials>
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link> <link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
</tutorials> </tutorials>
<methods> <methods>
<method name="get_input" qualifiers="const"> <method name="get_input" qualifiers="const" deprecated="Use through [XRControllerTracker].">
<return type="Variant" /> <return type="Variant" />
<param index="0" name="name" type="StringName" /> <param index="0" name="name" type="StringName" />
<description> <description>
@ -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. 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.
</description> </description>
</method> </method>
<method name="set_input"> <method name="set_input" deprecated="Use through [XRControllerTracker].">
<return type="void" /> <return type="void" />
<param index="0" name="name" type="StringName" /> <param index="0" name="name" type="StringName" />
<param index="1" name="value" type="Variant" /> <param index="1" name="value" type="Variant" />
@ -61,23 +61,12 @@
</method> </method>
</methods> </methods>
<members> <members>
<member name="description" type="String" setter="set_tracker_desc" getter="get_tracker_desc" default="&quot;&quot;">
The description of this tracker.
</member>
<member name="hand" type="int" setter="set_tracker_hand" getter="get_tracker_hand" enum="XRPositionalTracker.TrackerHand" default="0"> <member name="hand" type="int" setter="set_tracker_hand" getter="get_tracker_hand" enum="XRPositionalTracker.TrackerHand" default="0">
Defines which hand this tracker relates to. Defines which hand this tracker relates to.
</member> </member>
<member name="name" type="StringName" setter="set_tracker_name" getter="get_tracker_name" default="&amp;&quot;Unknown&quot;">
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
</member>
<member name="profile" type="String" setter="set_tracker_profile" getter="get_tracker_profile" default="&quot;&quot;"> <member name="profile" type="String" setter="set_tracker_profile" getter="get_tracker_profile" default="&quot;&quot;">
The profile associated with this tracker, interface dependent but will indicate the type of controller being tracked. The profile associated with this tracker, interface dependent but will indicate the type of controller being tracked.
</member> </member>
<member name="type" type="int" setter="set_tracker_type" getter="get_tracker_type" enum="XRServer.TrackerType" default="128">
The type of tracker.
</member>
</members> </members>
<signals> <signals>
<signal name="button_pressed"> <signal name="button_pressed">
@ -135,5 +124,8 @@
<constant name="TRACKER_HAND_RIGHT" value="2" enum="TrackerHand"> <constant name="TRACKER_HAND_RIGHT" value="2" enum="TrackerHand">
This tracker is the right hand controller. This tracker is the right hand controller.
</constant> </constant>
<constant name="TRACKER_HAND_MAX" value="3" enum="TrackerHand">
Represents the size of the [enum TrackerHand] enum.
</constant>
</constants> </constants>
</class> </class>

View File

@ -10,30 +10,6 @@
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link> <link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
</tutorials> </tutorials>
<methods> <methods>
<method name="add_body_tracker">
<return type="void" />
<param index="0" name="tracker_name" type="StringName" />
<param index="1" name="body_tracker" type="XRBodyTracker" />
<description>
Registers a new [XRBodyTracker] that tracks the joints of a body.
</description>
</method>
<method name="add_face_tracker">
<return type="void" />
<param index="0" name="tracker_name" type="StringName" />
<param index="1" name="face_tracker" type="XRFaceTracker" />
<description>
Registers a new [XRFaceTracker] that tracks the blend shapes of a face.
</description>
</method>
<method name="add_hand_tracker">
<return type="void" />
<param index="0" name="tracker_name" type="StringName" />
<param index="1" name="hand_tracker" type="XRHandTracker" />
<description>
Registers a new [XRHandTracker] that tracks the joints of a hand.
</description>
</method>
<method name="add_interface"> <method name="add_interface">
<return type="void" /> <return type="void" />
<param index="0" name="interface" type="XRInterface" /> <param index="0" name="interface" type="XRInterface" />
@ -43,9 +19,9 @@
</method> </method>
<method name="add_tracker"> <method name="add_tracker">
<return type="void" /> <return type="void" />
<param index="0" name="tracker" type="XRPositionalTracker" /> <param index="0" name="tracker" type="XRTracker" />
<description> <description>
Registers a new [XRPositionalTracker] that tracks a spatial location in real space. Registers a new [XRTracker] that tracks a physical object.
</description> </description>
</method> </method>
<method name="center_on_hmd"> <method name="center_on_hmd">
@ -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. 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.
</description> </description>
</method> </method>
<method name="get_body_tracker" qualifiers="const">
<return type="XRBodyTracker" />
<param index="0" name="tracker_name" type="StringName" />
<description>
Returns the [XRBodyTracker] with the given tracker name.
</description>
</method>
<method name="get_body_trackers" qualifiers="const">
<return type="Dictionary" />
<description>
Returns a dictionary of the registered body trackers. Each element of the dictionary is a tracker name mapping to the [XRBodyTracker] instance.
</description>
</method>
<method name="get_face_tracker" qualifiers="const">
<return type="XRFaceTracker" />
<param index="0" name="tracker_name" type="StringName" />
<description>
Returns the [XRFaceTracker] with the given tracker name.
</description>
</method>
<method name="get_face_trackers" qualifiers="const">
<return type="Dictionary" />
<description>
Returns a dictionary of the registered face trackers. Each element of the dictionary is a tracker name mapping to the [XRFaceTracker] instance.
</description>
</method>
<method name="get_hand_tracker" qualifiers="const">
<return type="XRHandTracker" />
<param index="0" name="tracker_name" type="StringName" />
<description>
Returns the [XRHandTracker] with the given tracker name.
</description>
</method>
<method name="get_hand_trackers" qualifiers="const">
<return type="Dictionary" />
<description>
Returns a dictionary of the registered hand trackers. Each element of the dictionary is a tracker name mapping to the [XRHandTracker] instance.
</description>
</method>
<method name="get_hmd_transform"> <method name="get_hmd_transform">
<return type="Transform3D" /> <return type="Transform3D" />
<description> <description>
@ -145,7 +82,7 @@
</description> </description>
</method> </method>
<method name="get_tracker" qualifiers="const"> <method name="get_tracker" qualifiers="const">
<return type="XRPositionalTracker" /> <return type="XRTracker" />
<param index="0" name="tracker_name" type="StringName" /> <param index="0" name="tracker_name" type="StringName" />
<description> <description>
Returns the positional tracker with the given [param tracker_name]. Returns the positional tracker with the given [param tracker_name].
@ -158,27 +95,6 @@
Returns a dictionary of trackers for [param tracker_types]. Returns a dictionary of trackers for [param tracker_types].
</description> </description>
</method> </method>
<method name="remove_body_tracker">
<return type="void" />
<param index="0" name="tracker_name" type="StringName" />
<description>
Removes a registered [XRBodyTracker].
</description>
</method>
<method name="remove_face_tracker">
<return type="void" />
<param index="0" name="tracker_name" type="StringName" />
<description>
Removes a registered [XRFaceTracker].
</description>
</method>
<method name="remove_hand_tracker">
<return type="void" />
<param index="0" name="tracker_name" type="StringName" />
<description>
Removes a registered [XRHandTracker].
</description>
</method>
<method name="remove_interface"> <method name="remove_interface">
<return type="void" /> <return type="void" />
<param index="0" name="interface" type="XRInterface" /> <param index="0" name="interface" type="XRInterface" />
@ -188,9 +104,9 @@
</method> </method>
<method name="remove_tracker"> <method name="remove_tracker">
<return type="void" /> <return type="void" />
<param index="0" name="tracker" type="XRPositionalTracker" /> <param index="0" name="tracker" type="XRTracker" />
<description> <description>
Removes this positional [param tracker]. Removes this [param tracker].
</description> </description>
</method> </method>
</methods> </methods>
@ -207,66 +123,6 @@
</member> </member>
</members> </members>
<signals> <signals>
<signal name="body_tracker_added">
<param index="0" name="tracker_name" type="StringName" />
<param index="1" name="body_tracker" type="XRBodyTracker" />
<description>
Emitted when a new body tracker is added.
</description>
</signal>
<signal name="body_tracker_removed">
<param index="0" name="tracker_name" type="StringName" />
<description>
Emitted when a body tracker is removed.
</description>
</signal>
<signal name="body_tracker_updated">
<param index="0" name="tracker_name" type="StringName" />
<param index="1" name="body_tracker" type="XRBodyTracker" />
<description>
Emitted when an existing body tracker is updated.
</description>
</signal>
<signal name="face_tracker_added">
<param index="0" name="tracker_name" type="StringName" />
<param index="1" name="face_tracker" type="XRFaceTracker" />
<description>
Emitted when a new face tracker is added.
</description>
</signal>
<signal name="face_tracker_removed">
<param index="0" name="tracker_name" type="StringName" />
<description>
Emitted when a face tracker is removed.
</description>
</signal>
<signal name="face_tracker_updated">
<param index="0" name="tracker_name" type="StringName" />
<param index="1" name="face_tracker" type="XRFaceTracker" />
<description>
Emitted when an existing face tracker is updated.
</description>
</signal>
<signal name="hand_tracker_added">
<param index="0" name="tracker_name" type="StringName" />
<param index="1" name="hand_tracker" type="XRHandTracker" />
<description>
Emitted when a new hand tracker is added.
</description>
</signal>
<signal name="hand_tracker_removed">
<param index="0" name="tracker_name" type="StringName" />
<description>
Emitted when a hand tracker is removed.
</description>
</signal>
<signal name="hand_tracker_updated">
<param index="0" name="tracker_name" type="StringName" />
<param index="1" name="hand_tracker" type="XRHandTracker" />
<description>
Emitted when an existing hand tracker is updated.
</description>
</signal>
<signal name="interface_added"> <signal name="interface_added">
<param index="0" name="interface_name" type="StringName" /> <param index="0" name="interface_name" type="StringName" />
<description> <description>
@ -314,6 +170,15 @@
<constant name="TRACKER_ANCHOR" value="8" enum="TrackerType"> <constant name="TRACKER_ANCHOR" value="8" enum="TrackerType">
The tracker tracks the location and size of an AR anchor. The tracker tracks the location and size of an AR anchor.
</constant> </constant>
<constant name="TRACKER_HAND" value="16" enum="TrackerType">
The tracker tracks the location and joints of a hand.
</constant>
<constant name="TRACKER_BODY" value="32" enum="TrackerType">
The tracker tracks the location and joints of a body.
</constant>
<constant name="TRACKER_FACE" value="64" enum="TrackerType">
The tracker tracks the expressions of a face.
</constant>
<constant name="TRACKER_ANY_KNOWN" value="127" enum="TrackerType"> <constant name="TRACKER_ANY_KNOWN" value="127" enum="TrackerType">
Used internally to filter trackers of any known type. Used internally to filter trackers of any known type.
</constant> </constant>

30
doc/classes/XRTracker.xml Normal file
View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="XRTracker" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A tracked object.
</brief_description>
<description>
This object is the base of all XR trackers.
</description>
<tutorials>
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
</tutorials>
<members>
<member name="description" type="String" setter="set_tracker_desc" getter="get_tracker_desc" default="&quot;&quot;">
The description of this tracker.
</member>
<member name="name" type="StringName" setter="set_tracker_name" getter="get_tracker_name" default="&amp;&quot;Unknown&quot;">
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
</member>
<member name="type" type="int" setter="set_tracker_type" getter="get_tracker_type" enum="XRServer.TrackerType" default="128">
The type of tracker.
</member>
</members>
</class>

View File

@ -0,0 +1 @@
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><path d="m4 12v1c0 .552.448 1 1 1-.552 0-1 .448-1 1v1h1v-1h1v1h1v-1c0-.552-.448-1-1-1 .552 0 1-.448 1-1v-1h-1v1h-1v-1zm5 0v4h1v-1h1v1h1v-1c-.001-.176-.048-.348-.137-.5.089-.152.136-.324.137-.5v-1c0-.552-.448-1-1-1zm1 1h1v1h-1z"/><path d="m11.384 9.462v-2.155c1.613-.944 2.156-3.016 1.213-4.631-.603-1.033-1.709-1.67-2.905-1.676h-3.385c-1.869.008-3.377 1.532-3.368 3.401.005 1.197.643 2.301 1.676 2.906v2.155c0 .934.758 1.692 1.692 1.692h3.385c.935 0 1.692-.758 1.692-1.692zm-4.23-4.231h1.692v.846h-1.692zm-2.539-.846c0-.468.378-.846.847-.846.468 0 .846.378.846.846 0 .467-.378.846-.846.846-.469 0-.847-.379-.847-.846zm5.923 5.077h-.846v-.847h-.846v.846h-1.692v-.846h-.847v.846h-.846v-2.538h.846v.846h.847v-.846h1.692v.846h.846v-.846h.846zm-.846-5.077c0-.468.378-.846.846-.846s.846.378.846.846c0 .467-.378.846-.846.846s-.846-.379-.846-.846z"/></g></svg>

After

Width:  |  Height:  |  Size: 953 B

View File

@ -0,0 +1 @@
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="6" fill="none" r="4" stroke="#fc7f7f" stroke-width="2"/><path d="m4 12v1c0 .552.448 1 1 1-.552 0-1 .448-1 1v1h1v-1h1v1h1v-1c0-.552-.448-1-1-1 .552 0 1-.448 1-1v-1h-1v1h-1v-1zm5 0v4h1v-1h1v1h1v-1c-.001-.176-.048-.348-.137-.5.089-.152.136-.324.137-.5v-1c0-.552-.448-1-1-1zm1 1h1v1h-1z" fill="#fc7f7f"/></svg>

After

Width:  |  Height:  |  Size: 408 B

View File

@ -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. They have been replaced by a safer API due to performance concerns. Compatibility method registered.
GH-90747 GH-90747
-------- --------
Validate extension JSON: API was removed: classes/NavigationRegion2D/methods/get_avoidance_layers 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 Validate extension JSON: API was removed: classes/NavigationRegion2D/properties/constrain_avoidance
Experimental NavigationRegion2D feature "constrain_avoidance" was discontinued with no replacement. 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.

View File

@ -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. 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.
</description> </description>
</method> </method>
<method name="get_hand_joint_angular_velocity" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_angular_velocity] obtained from [method XRServer.get_hand_tracker] instead."> <method name="get_hand_joint_angular_velocity" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_angular_velocity] obtained from [method XRServer.get_tracker] instead.">
<return type="Vector3" /> <return type="Vector3" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" /> <param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
@ -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]! 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]!
</description> </description>
</method> </method>
<method name="get_hand_joint_flags" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_flags] obtained from [method XRServer.get_hand_tracker] instead."> <method name="get_hand_joint_flags" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_flags] obtained from [method XRServer.get_tracker] instead.">
<return type="int" enum="OpenXRInterface.HandJointFlags" is_bitfield="true" /> <return type="int" enum="OpenXRInterface.HandJointFlags" is_bitfield="true" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" /> <param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
@ -39,7 +39,7 @@
If handtracking is enabled, returns flags that inform us of the validity of the tracking data. If handtracking is enabled, returns flags that inform us of the validity of the tracking data.
</description> </description>
</method> </method>
<method name="get_hand_joint_linear_velocity" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_linear_velocity] obtained from [method XRServer.get_hand_tracker] instead."> <method name="get_hand_joint_linear_velocity" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_linear_velocity] obtained from [method XRServer.get_tracker] instead.">
<return type="Vector3" /> <return type="Vector3" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" /> <param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
@ -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! 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!
</description> </description>
</method> </method>
<method name="get_hand_joint_position" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_transform] obtained from [method XRServer.get_hand_tracker] instead."> <method name="get_hand_joint_position" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_transform] obtained from [method XRServer.get_tracker] instead.">
<return type="Vector3" /> <return type="Vector3" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" /> <param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
@ -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! 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!
</description> </description>
</method> </method>
<method name="get_hand_joint_radius" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_radius] obtained from [method XRServer.get_hand_tracker] instead."> <method name="get_hand_joint_radius" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_radius] obtained from [method XRServer.get_tracker] instead.">
<return type="float" /> <return type="float" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" /> <param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
@ -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! 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!
</description> </description>
</method> </method>
<method name="get_hand_joint_rotation" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_transform] obtained from [method XRServer.get_hand_tracker] instead."> <method name="get_hand_joint_rotation" qualifiers="const" deprecated="Use [method XRHandTracker.get_hand_joint_transform] obtained from [method XRServer.get_tracker] instead.">
<return type="Quaternion" /> <return type="Quaternion" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" /> <param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
@ -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. If handtracking is enabled, returns the rotation of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR.
</description> </description>
</method> </method>
<method name="get_hand_tracking_source" qualifiers="const" deprecated="Use [member XRHandTracker.hand_tracking_source] obtained from [method XRServer.get_hand_tracker] instead."> <method name="get_hand_tracking_source" qualifiers="const" deprecated="Use [member XRHandTracker.hand_tracking_source] obtained from [method XRServer.get_tracker] instead.">
<return type="int" enum="OpenXRInterface.HandTrackedSource" /> <return type="int" enum="OpenXRInterface.HandTrackedSource" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" /> <param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
<description> <description>

View File

@ -196,7 +196,8 @@ void OpenXRHandTrackingExtension::on_process() {
Ref<XRHandTracker> godot_tracker; Ref<XRHandTracker> godot_tracker;
godot_tracker.instantiate(); godot_tracker.instantiate();
godot_tracker->set_hand(i == 0 ? XRHandTracker::HAND_LEFT : XRHandTracker::HAND_RIGHT); 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].godot_tracker = godot_tracker;
hand_trackers[i].is_initialized = true; 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 // 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; const XrPosef &palm = hand_trackers[i].joint_locations[XR_HAND_JOINT_PALM_EXT].pose;
if ( 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 || 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 hand_trackers[i].locations.isActive = false; // workaround, make sure its inactive
} }
@ -249,6 +249,8 @@ void OpenXRHandTrackingExtension::on_process() {
const XrPosef &pose = location.pose; const XrPosef &pose = location.pose;
Transform3D transform; Transform3D transform;
Vector3 linear_velocity;
Vector3 angular_velocity;
BitField<XRHandTracker::HandJointFlags> flags; BitField<XRHandTracker::HandJointFlags> flags;
if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) { 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) { if (location.locationFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_LINEAR_VELOCITY_VALID); 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) { if (location.locationFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
flags.set_flag(XRHandTracker::HAND_JOINT_FLAG_ANGULAR_VELOCITY_VALID); 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_flags((XRHandTracker::HandJoint)joint, flags);
godot_tracker->set_hand_joint_transform((XRHandTracker::HandJoint)joint, transform); godot_tracker->set_hand_joint_transform((XRHandTracker::HandJoint)joint, transform);
godot_tracker->set_hand_joint_radius((XRHandTracker::HandJoint)joint, location.radius); godot_tracker->set_hand_joint_radius((XRHandTracker::HandJoint)joint, location.radius);
if (joint == XR_HAND_JOINT_PALM_EXT) {
XRHandTracker::HandTrackingSource source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN; XRHandTracker::HandTrackingSource source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN;
if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) { if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_UNOBSTRUCTED; source = XRHandTracker::HAND_TRACKING_SOURCE_UNOBSTRUCTED;
} else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) { } else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_CONTROLLER; source = XRHandTracker::HAND_TRACKING_SOURCE_CONTROLLER;
} }
godot_tracker->set_hand_tracking_source(source); godot_tracker->set_hand_tracking_source(source);
godot_tracker->set_pose("default", transform, linear_velocity, angular_velocity);
}
} }
} else { } else {
godot_tracker->set_has_tracking_data(false); 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].is_initialized = false;
hand_trackers[i].hand_tracker = XR_NULL_HANDLE; 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);
} }
} }
} }

View File

@ -35,6 +35,7 @@
#include "servers/rendering/rendering_server_globals.h" #include "servers/rendering/rendering_server_globals.h"
#include "extensions/openxr_eye_gaze_interaction.h" #include "extensions/openxr_eye_gaze_interaction.h"
#include "thirdparty/openxr/include/openxr/openxr.h"
void OpenXRInterface::_bind_methods() { void OpenXRInterface::_bind_methods() {
// lifecycle signals // 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 // These are hardcoded in OpenXR, note that they will only be available if added to our action map
PackedStringArray arr = { PackedStringArray arr = {
"left_hand", // /user/hand/left is mapped to our defaults "head", // XRPositionalTracker for the users head (Mapped from OpenXR /user/head)
"right_hand", // /user/hand/right is mapped to our defaults "left_hand", // XRControllerTracker for the users left hand (Mapped from OpenXR /user/hand/left)
"/user/treadmill", "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()) { 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); RID tracker_rid = openxr_api->tracker_create(p_tracker_name);
ERR_FAIL_COND_V(tracker_rid.is_null(), nullptr); ERR_FAIL_COND_V(tracker_rid.is_null(), nullptr);
// create our positional tracker // Create our controller tracker.
Ref<XRPositionalTracker> positional_tracker; Ref<XRControllerTracker> controller_tracker;
positional_tracker.instantiate(); controller_tracker.instantiate();
// We have standardized some names to make things nicer to the user so lets recognize the toplevel paths related to these. // 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") { if (p_tracker_name == "/user/hand/left") {
positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); controller_tracker->set_tracker_name("left_hand");
positional_tracker->set_tracker_name("left_hand"); controller_tracker->set_tracker_desc("Left hand controller");
positional_tracker->set_tracker_desc("Left hand controller"); controller_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT);
positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT);
} else if (p_tracker_name == "/user/hand/right") { } else if (p_tracker_name == "/user/hand/right") {
positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); controller_tracker->set_tracker_name("right_hand");
positional_tracker->set_tracker_name("right_hand"); controller_tracker->set_tracker_desc("Right hand controller");
positional_tracker->set_tracker_desc("Right hand controller"); controller_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT);
positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT);
} else { } else {
positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); controller_tracker->set_tracker_name(p_tracker_name);
positional_tracker->set_tracker_name(p_tracker_name); controller_tracker->set_tracker_desc(p_tracker_name);
positional_tracker->set_tracker_desc(p_tracker_name);
} }
positional_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE); controller_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE);
xr_server->add_tracker(positional_tracker); xr_server->add_tracker(controller_tracker);
// create a new entry // create a new entry
tracker = memnew(Tracker); tracker = memnew(Tracker);
tracker->tracker_name = p_tracker_name; tracker->tracker_name = p_tracker_name;
tracker->tracker_rid = tracker_rid; tracker->tracker_rid = tracker_rid;
tracker->positional_tracker = positional_tracker; tracker->controller_tracker = controller_tracker;
tracker->interaction_profile = RID(); tracker->interaction_profile = RID();
trackers.push_back(tracker); 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()) { if (p_interaction_profile.is_null()) {
print_verbose("OpenXR: Interaction profile for " + tracker->tracker_name + " changed to " + INTERACTION_PROFILE_NONE); 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 { } else {
String name = openxr_api->interaction_profile_get_name(p_interaction_profile); String name = openxr_api->interaction_profile_get_name(p_interaction_profile);
print_verbose("OpenXR: Interaction profile for " + tracker->tracker_name + " changed to " + name); 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) { void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
ERR_FAIL_NULL(openxr_api); 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 // 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 // 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) { switch (action->action_type) {
case OpenXRAction::OPENXR_ACTION_BOOL: { case OpenXRAction::OPENXR_ACTION_BOOL: {
bool pressed = openxr_api->get_action_bool(action->action_rid, p_tracker->tracker_rid); 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; } break;
case OpenXRAction::OPENXR_ACTION_FLOAT: { case OpenXRAction::OPENXR_ACTION_FLOAT: {
real_t value = openxr_api->get_action_float(action->action_rid, p_tracker->tracker_rid); 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; } break;
case OpenXRAction::OPENXR_ACTION_VECTOR2: { case OpenXRAction::OPENXR_ACTION_VECTOR2: {
Vector2 value = openxr_api->get_action_vector2(action->action_rid, p_tracker->tracker_rid); 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; } break;
case OpenXRAction::OPENXR_ACTION_POSE: { case OpenXRAction::OPENXR_ACTION_POSE: {
Transform3D transform; 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); 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) { 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 { } else {
p_tracker->positional_tracker->invalidate_pose(action->action_name); p_tracker->controller_tracker->invalidate_pose(action->action_name);
} }
} break; } break;
default: { default: {
@ -567,8 +570,8 @@ void OpenXRInterface::free_trackers() {
Tracker *tracker = trackers[i]; Tracker *tracker = trackers[i];
openxr_api->tracker_free(tracker->tracker_rid); openxr_api->tracker_free(tracker->tracker_rid);
xr_server->remove_tracker(tracker->positional_tracker); xr_server->remove_tracker(tracker->controller_tracker);
tracker->positional_tracker.unref(); tracker->controller_tracker.unref();
memdelete(tracker); memdelete(tracker);
} }
@ -1005,7 +1008,7 @@ void OpenXRInterface::handle_hand_tracking(const String &p_path, OpenXRHandTrack
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) { if (hand_tracking_ext && hand_tracking_ext->get_active()) {
OpenXRInterface::Tracker *tracker = find_tracker(p_path); 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); 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)) { 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); 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 { } else {
tracker->positional_tracker->invalidate_pose("skeleton"); tracker->controller_tracker->invalidate_pose("skeleton");
} }
} }
} }

View File

@ -35,8 +35,8 @@
#include "extensions/openxr_hand_tracking_extension.h" #include "extensions/openxr_hand_tracking_extension.h"
#include "openxr_api.h" #include "openxr_api.h"
#include "servers/xr/xr_controller_tracker.h"
#include "servers/xr/xr_interface.h" #include "servers/xr/xr_interface.h"
#include "servers/xr/xr_positional_tracker.h"
// declare some default strings // declare some default strings
#define INTERACTION_PROFILE_NONE "/interaction_profiles/none" #define INTERACTION_PROFILE_NONE "/interaction_profiles/none"
@ -73,7 +73,7 @@ private:
struct Tracker { // A tracker we've registered with OpenXR struct Tracker { // A tracker we've registered with OpenXR
String tracker_name; // Name of our tracker (can be altered from the action map) String tracker_name; // Name of our tracker (can be altered from the action map)
Vector<Action *> actions; // Actions related to this tracker Vector<Action *> actions; // Actions related to this tracker
Ref<XRPositionalTracker> positional_tracker; // Our positional tracker object that holds our tracker state Ref<XRControllerTracker> controller_tracker; // Our positional tracker object that holds our tracker state
RID tracker_rid; // RID of the tracker registered with our OpenXR API 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) RID interaction_profile; // RID of the interaction profile bound to this tracker (can be null)
}; };

View File

@ -114,10 +114,10 @@
</description> </description>
</method> </method>
<method name="get_input_source_tracker" qualifiers="const"> <method name="get_input_source_tracker" qualifiers="const">
<return type="XRPositionalTracker" /> <return type="XRControllerTracker" />
<param index="0" name="input_source_id" type="int" /> <param index="0" name="input_source_id" type="int" />
<description> <description>
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. 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: Use this method to get information about the input source that triggered one of these signals:
- [signal selectstart] - [signal selectstart]

View File

@ -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<XRPositionalTracker> 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

View File

@ -29,6 +29,7 @@
/**************************************************************************/ /**************************************************************************/
#include "webxr_interface.h" #include "webxr_interface.h"
#include "webxr_interface.compat.inc"
#include <stdlib.h> #include <stdlib.h>

View File

@ -31,8 +31,8 @@
#ifndef WEBXR_INTERFACE_H #ifndef WEBXR_INTERFACE_H
#define WEBXR_INTERFACE_H #define WEBXR_INTERFACE_H
#include "servers/xr/xr_controller_tracker.h"
#include "servers/xr/xr_interface.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. The WebXR interface is a VR/AR interface that can be used on the web.
@ -44,6 +44,11 @@ class WebXRInterface : public XRInterface {
protected: protected:
static void _bind_methods(); static void _bind_methods();
#ifndef DISABLE_DEPRECATED
static void _bind_compatibility_methods();
Ref<XRPositionalTracker> _get_input_source_tracker_bind_compat_90645(int p_input_source_id) const;
#endif
public: public:
enum TargetRayMode { enum TargetRayMode {
TARGET_RAY_MODE_UNKNOWN, TARGET_RAY_MODE_UNKNOWN,
@ -64,7 +69,7 @@ public:
virtual String get_reference_space_type() const = 0; virtual String get_reference_space_type() const = 0;
virtual String get_enabled_features() const = 0; virtual String get_enabled_features() const = 0;
virtual bool is_input_source_active(int p_input_source_id) const = 0; virtual bool is_input_source_active(int p_input_source_id) const = 0;
virtual Ref<XRPositionalTracker> get_input_source_tracker(int p_input_source_id) const = 0; virtual Ref<XRControllerTracker> 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 TargetRayMode get_input_source_target_ray_mode(int p_input_source_id) const = 0;
virtual String get_visibility_state() const = 0; virtual String get_visibility_state() const = 0;
virtual float get_display_refresh_rate() const = 0; virtual float get_display_refresh_rate() const = 0;

View File

@ -164,8 +164,8 @@ bool WebXRInterfaceJS::is_input_source_active(int p_input_source_id) const {
return input_sources[p_input_source_id].active; return input_sources[p_input_source_id].active;
} }
Ref<XRPositionalTracker> WebXRInterfaceJS::get_input_source_tracker(int p_input_source_id) const { Ref<XRControllerTracker> WebXRInterfaceJS::get_input_source_tracker(int p_input_source_id) const {
ERR_FAIL_INDEX_V(p_input_source_id, input_source_count, Ref<XRPositionalTracker>()); ERR_FAIL_INDEX_V(p_input_source_id, input_source_count, Ref<XRControllerTracker>());
return input_sources[p_input_source_id].tracker; return input_sources[p_input_source_id].tracker;
} }
@ -307,7 +307,7 @@ void WebXRInterfaceJS::uninitialize() {
for (int i = 0; i < HAND_MAX; i++) { for (int i = 0; i < HAND_MAX; i++) {
if (hand_trackers[i].is_valid()) { 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(); 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.target_ray_mode = (WebXRInterface::TargetRayMode)tmp_target_ray_mode;
input_source.touch_index = touch_index; input_source.touch_index = touch_index;
Ref<XRPositionalTracker> &tracker = input_source.tracker; Ref<XRControllerTracker> &tracker = input_source.tracker;
if (tracker.is_null()) { if (tracker.is_null()) {
tracker.instantiate(); 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. // Input source id's 0 and 1 are always the left and right hands.
if (p_input_source_id < 2) { if (p_input_source_id < 2) {
tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
tracker->set_tracker_name(tracker_name); tracker->set_tracker_name(tracker_name);
tracker->set_tracker_desc(p_input_source_id == 0 ? "Left hand controller" : "Right hand controller"); 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); 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())) { if (unlikely(hand_tracker.is_null())) {
hand_tracker.instantiate(); hand_tracker.instantiate();
hand_tracker->set_hand(p_input_source_id == 0 ? XRHandTracker::HAND_LEFT : XRHandTracker::HAND_RIGHT); 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. // These flags always apply, since WebXR doesn't give us enough insight to be more fine grained.
BitField<XRHandTracker::HandJointFlags> 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); BitField<XRHandTracker::HandJointFlags> 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; 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); hand_tracker->set_has_tracking_data(true);
@ -746,10 +746,12 @@ void WebXRInterfaceJS::_update_input_source(int p_input_source_id) {
Transform3D palm_transform; 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; 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_hand_joint_transform(XRHandTracker::HAND_JOINT_PALM, palm_transform);
hand_tracker->set_pose("default", palm_transform, Vector3(), Vector3());
} }
} else if (hand_tracker.is_valid()) { } else if (hand_tracker.is_valid()) {
hand_tracker->set_has_tracking_data(false); hand_tracker->set_has_tracking_data(false);
hand_tracker->invalidate_pose("default");
} }
} }
} }

View File

@ -33,6 +33,8 @@
#ifdef WEB_ENABLED #ifdef WEB_ENABLED
#include "servers/xr/xr_controller_tracker.h"
#include "servers/xr/xr_hand_tracker.h"
#include "webxr_interface.h" #include "webxr_interface.h"
/** /**
@ -68,7 +70,7 @@ private:
static constexpr uint8_t input_source_count = 16; static constexpr uint8_t input_source_count = 16;
struct InputSource { struct InputSource {
Ref<XRPositionalTracker> tracker; Ref<XRControllerTracker> tracker;
bool active = false; bool active = false;
TargetRayMode target_ray_mode; TargetRayMode target_ray_mode;
int touch_index = -1; int touch_index = -1;
@ -102,7 +104,7 @@ public:
virtual String get_reference_space_type() const override; virtual String get_reference_space_type() const override;
virtual String get_enabled_features() const override; virtual String get_enabled_features() const override;
virtual bool is_input_source_active(int p_input_source_id) const override; virtual bool is_input_source_active(int p_input_source_id) const override;
virtual Ref<XRPositionalTracker> get_input_source_tracker(int p_input_source_id) const override; virtual Ref<XRControllerTracker> 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 TargetRayMode get_input_source_target_ray_mode(int p_input_source_id) const override;
virtual String get_visibility_state() const override; virtual String get_visibility_state() const override;
virtual PackedVector3Array get_play_area() const override; virtual PackedVector3Array get_play_area() const override;

View File

@ -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("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("get_bone_update"), &XRBodyModifier3D::get_bone_update);
ClassDB::bind_method(D_METHOD("set_show_when_tracked", "show"), &XRBodyModifier3D::set_show_when_tracked); ADD_PROPERTY(PropertyInfo(Variant::STRING, "body_tracker", PROPERTY_HINT_ENUM_SUGGESTION, "/user/body_tracker"), "set_body_tracker", "get_body_tracker");
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::INT, "body_update", PROPERTY_HINT_FLAGS, "Upper Body,Lower Body,Hands"), "set_body_update", "get_body_update"); 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::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_UPPER_BODY);
BIND_BITFIELD_FLAG(BODY_UPDATE_LOWER_BODY); BIND_BITFIELD_FLAG(BODY_UPDATE_LOWER_BODY);
@ -86,14 +82,6 @@ XRBodyModifier3D::BoneUpdate XRBodyModifier3D::get_bone_update() const {
return bone_update; 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() { void XRBodyModifier3D::_get_joint_data() {
// Table of Godot Humanoid bone names. // Table of Godot Humanoid bone names.
static const String bone_names[XRBodyTracker::JOINT_MAX] = { static const String bone_names[XRBodyTracker::JOINT_MAX] = {
@ -189,7 +177,7 @@ void XRBodyModifier3D::_get_joint_data() {
joints[i].parent_joint = -1; joints[i].parent_joint = -1;
} }
Skeleton3D *skeleton = get_skeleton(); const Skeleton3D *skeleton = get_skeleton();
if (!skeleton) { if (!skeleton) {
return; return;
} }
@ -257,27 +245,22 @@ void XRBodyModifier3D::_process_modification() {
return; return;
} }
XRServer *xr_server = XRServer::get_singleton(); const XRServer *xr_server = XRServer::get_singleton();
if (!xr_server) { if (!xr_server) {
return; return;
} }
Ref<XRBodyTracker> tracker = xr_server->get_body_tracker(tracker_name); const Ref<XRBodyTracker> tracker = xr_server->get_tracker(tracker_name);
if (tracker.is_null()) { if (!tracker.is_valid()) {
return; return;
} }
// Handle no tracking data. // Skip if no tracking data.
if (!tracker->get_has_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; return;
} }
// Get the world and skeleton scale. // Get the world and skeleton scale.
const float ws = xr_server->get_world_scale();
const float ss = skeleton->get_motion_scale(); const float ss = skeleton->get_motion_scale();
// Read the relevant tracking data. This applies the skeleton motion scale to // 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 (!has_valid_data[XRBodyTracker::JOINT_ROOT]) {
// If tracking-state determines visibility then hide the node.
if (show_when_tracked) {
set_visible(false);
}
return; return;
} }
@ -331,16 +310,6 @@ void XRBodyModifier3D::_process_modification() {
// Always update the bone rotation. // Always update the bone rotation.
skeleton->set_bone_pose_rotation(joints[joint].bone, Quaternion(relative_transform.basis)); 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<XRBodyTracker> &p_tracker) { void XRBodyModifier3D::_tracker_changed(const StringName &p_tracker_name, const Ref<XRBodyTracker> &p_tracker) {

View File

@ -66,9 +66,6 @@ public:
void set_bone_update(BoneUpdate p_bone_update); void set_bone_update(BoneUpdate p_bone_update);
BoneUpdate get_bone_update() const; 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); void _notification(int p_what);
protected: protected:
@ -83,10 +80,9 @@ private:
int parent_joint = -1; int parent_joint = -1;
}; };
StringName tracker_name = "/user/body"; StringName tracker_name = "/user/body_tracker";
BitField<BodyUpdate> body_update = BODY_UPDATE_UPPER_BODY | BODY_UPDATE_LOWER_BODY | BODY_UPDATE_HANDS; BitField<BodyUpdate> body_update = BODY_UPDATE_UPPER_BODY | BODY_UPDATE_LOWER_BODY | BODY_UPDATE_HANDS;
BoneUpdate bone_update = BONE_UPDATE_FULL; BoneUpdate bone_update = BONE_UPDATE_FULL;
bool show_when_tracked = true;
JointData joints[XRBodyTracker::JOINT_MAX]; JointData joints[XRBodyTracker::JOINT_MAX];
void _get_joint_data(); void _get_joint_data();

View File

@ -495,7 +495,7 @@ static void remove_driven_unified_blend_shapes(RBMap<int, int> &p_blend_mapping)
void XRFaceModifier3D::_bind_methods() { void XRFaceModifier3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_face_tracker", "tracker_name"), &XRFaceModifier3D::set_face_tracker); 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); 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("set_target", "target"), &XRFaceModifier3D::set_target);
ClassDB::bind_method(D_METHOD("get_target"), &XRFaceModifier3D::get_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. // Get the face tracker.
const Ref<XRFaceTracker> p = xr_server->get_face_tracker(tracker_name); const Ref<XRFaceTracker> tracker = xr_server->get_tracker(tracker_name);
if (!p.is_valid()) { if (!tracker.is_valid()) {
return; return;
} }
@ -588,7 +588,7 @@ void XRFaceModifier3D::_update_face_blends() const {
} }
// Get the blend weights. // 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. // Apply all the face blend weights to the mesh.
for (const KeyValue<int, int> &it : blend_mapping) { for (const KeyValue<int, int> &it : blend_mapping) {

View File

@ -47,7 +47,7 @@ class XRFaceModifier3D : public Node3D {
GDCLASS(XRFaceModifier3D, Node3D); GDCLASS(XRFaceModifier3D, Node3D);
private: private:
StringName tracker_name = "/user/head"; StringName tracker_name = "/user/face_tracker";
NodePath target; NodePath target;
// Map from XRFaceTracker blend shape index to mesh blend shape index. // Map from XRFaceTracker blend shape index to mesh blend shape index.

View File

@ -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("set_bone_update", "bone_update"), &XRHandModifier3D::set_bone_update);
ClassDB::bind_method(D_METHOD("get_bone_update"), &XRHandModifier3D::get_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"); 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); BIND_ENUM_CONSTANT(BONE_UPDATE_FULL);
@ -111,22 +111,30 @@ void XRHandModifier3D::_get_joint_data() {
joints[i].parent_joint = -1; joints[i].parent_joint = -1;
} }
Skeleton3D *skeleton = get_skeleton(); const Skeleton3D *skeleton = get_skeleton();
if (!skeleton) { if (!skeleton) {
return; return;
} }
XRServer *xr_server = XRServer::get_singleton(); const XRServer *xr_server = XRServer::get_singleton();
if (!xr_server) { if (!xr_server) {
return; return;
} }
Ref<XRHandTracker> tracker = xr_server->get_hand_tracker(tracker_name); const Ref<XRHandTracker> tracker = xr_server->get_tracker(tracker_name);
if (tracker.is_null()) { if (tracker.is_null()) {
return; 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. // Find the skeleton-bones associated with each joint.
int bones[XRHandTracker::HAND_JOINT_MAX]; int bones[XRHandTracker::HAND_JOINT_MAX];
@ -176,18 +184,22 @@ void XRHandModifier3D::_process_modification() {
return; return;
} }
XRServer *xr_server = XRServer::get_singleton(); const XRServer *xr_server = XRServer::get_singleton();
if (!xr_server) { if (!xr_server) {
return; return;
} }
Ref<XRHandTracker> tracker = xr_server->get_hand_tracker(tracker_name); const Ref<XRHandTracker> tracker = xr_server->get_tracker(tracker_name);
if (tracker.is_null()) { if (tracker.is_null()) {
return; return;
} }
// Skip if no tracking data
if (!tracker->get_has_tracking_data()) {
return;
}
// Get the world and skeleton scale. // Get the world and skeleton scale.
const float ws = xr_server->get_world_scale();
const float ss = skeleton->get_motion_scale(); const float ss = skeleton->get_motion_scale();
// We cache our transforms so we can quickly calculate local transforms. // We cache our transforms so we can quickly calculate local transforms.
@ -195,7 +207,6 @@ void XRHandModifier3D::_process_modification() {
Transform3D transforms[XRHandTracker::HAND_JOINT_MAX]; Transform3D transforms[XRHandTracker::HAND_JOINT_MAX];
Transform3D inv_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++) { for (int joint = 0; joint < XRHandTracker::HAND_JOINT_MAX; joint++) {
BitField<XRHandTracker::HandJointFlags> flags = tracker->get_hand_joint_flags((XRHandTracker::HandJoint)joint); BitField<XRHandTracker::HandJointFlags> flags = tracker->get_hand_joint_flags((XRHandTracker::HandJoint)joint);
has_valid_data[joint] = flags.has_flag(XRHandTracker::HAND_JOINT_FLAG_ORIENTATION_VALID); has_valid_data[joint] = flags.has_flag(XRHandTracker::HAND_JOINT_FLAG_ORIENTATION_VALID);
@ -207,7 +218,11 @@ void XRHandModifier3D::_process_modification() {
} }
} }
if (has_valid_data[XRHandTracker::HAND_JOINT_PALM]) { // 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++) { for (int joint = 0; joint < XRHandTracker::HAND_JOINT_MAX; joint++) {
// Get the skeleton bone (skip if none). // Get the skeleton bone (skip if none).
const int bone = joints[joint].bone; const int bone = joints[joint].bone;
@ -227,23 +242,9 @@ void XRHandModifier3D::_process_modification() {
// Always update the bone rotation. // Always update the bone rotation.
skeleton->set_bone_pose_rotation(joints[joint].bone, Quaternion(relative_transform.basis)); 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);
}
} else {
set_visible(false);
}
} }
void XRHandModifier3D::_tracker_changed(StringName p_tracker_name, const Ref<XRHandTracker> &p_tracker) { void XRHandModifier3D::_tracker_changed(StringName p_tracker_name, XRServer::TrackerType p_tracker_type) {
if (tracker_name == p_tracker_name) { if (tracker_name == p_tracker_name) {
_get_joint_data(); _get_joint_data();
} }
@ -258,9 +259,9 @@ void XRHandModifier3D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_ENTER_TREE: {
XRServer *xr_server = XRServer::get_singleton(); XRServer *xr_server = XRServer::get_singleton();
if (xr_server) { if (xr_server) {
xr_server->connect("hand_tracker_added", callable_mp(this, &XRHandModifier3D::_tracker_changed)); xr_server->connect("tracker_added", callable_mp(this, &XRHandModifier3D::_tracker_changed));
xr_server->connect("hand_tracker_updated", callable_mp(this, &XRHandModifier3D::_tracker_changed)); xr_server->connect("tracker_updated", callable_mp(this, &XRHandModifier3D::_tracker_changed));
xr_server->connect("hand_tracker_removed", callable_mp(this, &XRHandModifier3D::_tracker_changed).bind(Ref<XRHandTracker>())); xr_server->connect("tracker_removed", callable_mp(this, &XRHandModifier3D::_tracker_changed));
} }
_get_joint_data(); _get_joint_data();
@ -268,9 +269,9 @@ void XRHandModifier3D::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
XRServer *xr_server = XRServer::get_singleton(); XRServer *xr_server = XRServer::get_singleton();
if (xr_server) { if (xr_server) {
xr_server->disconnect("hand_tracker_added", callable_mp(this, &XRHandModifier3D::_tracker_changed)); xr_server->disconnect("tracker_added", callable_mp(this, &XRHandModifier3D::_tracker_changed));
xr_server->disconnect("hand_tracker_updated", callable_mp(this, &XRHandModifier3D::_tracker_changed)); xr_server->disconnect("tracker_updated", callable_mp(this, &XRHandModifier3D::_tracker_changed));
xr_server->disconnect("hand_tracker_removed", callable_mp(this, &XRHandModifier3D::_tracker_changed).bind(Ref<XRHandTracker>())); xr_server->disconnect("tracker_removed", callable_mp(this, &XRHandModifier3D::_tracker_changed));
} }
for (int i = 0; i < XRHandTracker::HAND_JOINT_MAX; i++) { for (int i = 0; i < XRHandTracker::HAND_JOINT_MAX; i++) {

View File

@ -69,12 +69,12 @@ private:
int parent_joint = -1; int parent_joint = -1;
}; };
StringName tracker_name = "/user/left"; StringName tracker_name = "/user/hand_tracker/left";
BoneUpdate bone_update = BONE_UPDATE_FULL; BoneUpdate bone_update = BONE_UPDATE_FULL;
JointData joints[XRHandTracker::HAND_JOINT_MAX]; JointData joints[XRHandTracker::HAND_JOINT_MAX];
void _get_joint_data(); void _get_joint_data();
void _tracker_changed(StringName p_tracker_name, const Ref<XRHandTracker> &p_tracker); void _tracker_changed(StringName p_tracker_name, XRServer::TrackerType p_tracker_type);
}; };
VARIANT_ENUM_CAST(XRHandModifier3D::BoneUpdate) VARIANT_ENUM_CAST(XRHandModifier3D::BoneUpdate)

View File

@ -80,10 +80,11 @@ PackedStringArray XRCamera3D::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings(); PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible() && is_inside_tree()) { if (is_visible() && is_inside_tree()) {
// must be child node of XROrigin3D! // Warn if the node has a parent which isn't an XROrigin3D!
XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); Node *parent = get_parent();
if (origin == nullptr) { XROrigin3D *origin = Object::cast_to<XROrigin3D>(parent);
warnings.push_back(RTR("XRCamera3D must have an XROrigin3D node as its 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); 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"); 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_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_has_tracking_data"), &XRNode3D::get_has_tracking_data);
ClassDB::bind_method(D_METHOD("get_pose"), &XRNode3D::get_pose); ClassDB::bind_method(D_METHOD("get_pose"), &XRNode3D::get_pose);
@ -296,6 +301,14 @@ StringName XRNode3D::get_pose_name() const {
return pose_name; 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 { bool XRNode3D::get_is_active() const {
if (tracker.is_null()) { if (tracker.is_null()) {
return false; return false;
@ -402,6 +415,11 @@ void XRNode3D::_set_has_tracking_data(bool p_has_tracking_data) {
// Handle change of has_tracking_data. // Handle change of has_tracking_data.
has_tracking_data = p_has_tracking_data; has_tracking_data = p_has_tracking_data;
emit_signal(SNAME("tracking_changed"), 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() { XRNode3D::XRNode3D() {
@ -428,11 +446,12 @@ PackedStringArray XRNode3D::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings(); PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible() && is_inside_tree()) { if (is_visible() && is_inside_tree()) {
// must be child node of XROrigin! // Warn if the node has a parent which isn't an XROrigin3D!
XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); Node *parent = get_parent();
if (origin == nullptr) { XROrigin3D *origin = Object::cast_to<XROrigin3D>(parent);
warnings.push_back(RTR("XRController3D must have an XROrigin3D node as its 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 == "") { if (tracker_name == "") {
warnings.push_back(RTR("No tracker name is set.")); warnings.push_back(RTR("No tracker name is set."));

View File

@ -79,6 +79,7 @@ private:
StringName tracker_name; StringName tracker_name;
StringName pose_name = "default"; StringName pose_name = "default";
bool has_tracking_data = false; bool has_tracking_data = false;
bool show_when_tracked = false;
protected: protected:
Ref<XRPositionalTracker> tracker; Ref<XRPositionalTracker> tracker;
@ -105,6 +106,9 @@ public:
bool get_is_active() const; bool get_is_active() const;
bool get_has_tracking_data() 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); 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<XRPose> get_pose(); Ref<XRPose> get_pose();

View File

@ -545,7 +545,7 @@ void register_scene_types() {
GDREGISTER_CLASS(Camera3D); GDREGISTER_CLASS(Camera3D);
GDREGISTER_CLASS(AudioListener3D); GDREGISTER_CLASS(AudioListener3D);
GDREGISTER_CLASS(XRCamera3D); GDREGISTER_CLASS(XRCamera3D);
GDREGISTER_ABSTRACT_CLASS(XRNode3D); GDREGISTER_CLASS(XRNode3D);
GDREGISTER_CLASS(XRController3D); GDREGISTER_CLASS(XRController3D);
GDREGISTER_CLASS(XRAnchor3D); GDREGISTER_CLASS(XRAnchor3D);
GDREGISTER_CLASS(XROrigin3D); GDREGISTER_CLASS(XROrigin3D);

View File

@ -94,6 +94,7 @@
#include "physics_server_3d_wrap_mt.h" #include "physics_server_3d_wrap_mt.h"
#include "servers/extensions/physics_server_3d_extension.h" #include "servers/extensions/physics_server_3d_extension.h"
#include "xr/xr_body_tracker.h" #include "xr/xr_body_tracker.h"
#include "xr/xr_controller_tracker.h"
#include "xr/xr_face_tracker.h" #include "xr/xr_face_tracker.h"
#include "xr/xr_hand_tracker.h" #include "xr/xr_hand_tracker.h"
#include "xr/xr_interface.h" #include "xr/xr_interface.h"
@ -325,12 +326,14 @@ void register_server_types() {
GDREGISTER_ABSTRACT_CLASS(XRInterface); GDREGISTER_ABSTRACT_CLASS(XRInterface);
GDREGISTER_CLASS(XRBodyTracker); GDREGISTER_CLASS(XRBodyTracker);
GDREGISTER_CLASS(XRControllerTracker);
GDREGISTER_CLASS(XRFaceTracker); GDREGISTER_CLASS(XRFaceTracker);
GDREGISTER_CLASS(XRHandTracker); GDREGISTER_CLASS(XRHandTracker);
GDREGISTER_CLASS(XRInterfaceExtension); // can't register this as virtual because we need a creation function for our extensions. GDREGISTER_CLASS(XRInterfaceExtension); // can't register this as virtual because we need a creation function for our extensions.
GDREGISTER_CLASS(XRPose); GDREGISTER_CLASS(XRPose);
GDREGISTER_CLASS(XRPositionalTracker); GDREGISTER_CLASS(XRPositionalTracker);
GDREGISTER_CLASS(XRServer); GDREGISTER_CLASS(XRServer);
GDREGISTER_ABSTRACT_CLASS(XRTracker);
#endif // _3D_DISABLED #endif // _3D_DISABLED
GDREGISTER_ABSTRACT_CLASS(NavigationServer3D); GDREGISTER_ABSTRACT_CLASS(NavigationServer3D);

View File

@ -134,6 +134,14 @@ void XRBodyTracker::_bind_methods() {
BIND_BITFIELD_FLAG(JOINT_FLAG_POSITION_TRACKED); 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) { void XRBodyTracker::set_has_tracking_data(bool p_has_tracking_data) {
has_tracking_data = 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()); ERR_FAIL_INDEX_V(p_joint, JOINT_MAX, Transform3D());
return joint_transforms[p_joint]; return joint_transforms[p_joint];
} }
XRBodyTracker::XRBodyTracker() {
type = XRServer::TRACKER_BODY;
}

View File

@ -31,10 +31,10 @@
#ifndef XR_BODY_TRACKER_H #ifndef XR_BODY_TRACKER_H
#define 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 { class XRBodyTracker : public XRPositionalTracker {
GDCLASS(XRBodyTracker, RefCounted); GDCLASS(XRBodyTracker, XRPositionalTracker);
_THREAD_SAFE_CLASS_ _THREAD_SAFE_CLASS_
public: public:
@ -140,6 +140,9 @@ public:
JOINT_FLAG_POSITION_TRACKED = 8, 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); void set_has_tracking_data(bool p_has_tracking_data);
bool get_has_tracking_data() const; bool get_has_tracking_data() const;
@ -152,6 +155,8 @@ public:
void set_joint_transform(Joint p_joint, const Transform3D &p_transform); void set_joint_transform(Joint p_joint, const Transform3D &p_transform);
Transform3D get_joint_transform(Joint p_joint) const; Transform3D get_joint_transform(Joint p_joint) const;
XRBodyTracker();
protected: protected:
static void _bind_methods(); static void _bind_methods();

View File

@ -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;
}

View File

@ -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

View File

@ -187,6 +187,10 @@ void XRFaceTracker::_bind_methods() {
ADD_PROPERTY_DEFAULT("blend_shapes", PackedFloat32Array()); // To prevent ludicrously large default values. 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 { float XRFaceTracker::get_blend_shape(BlendShapeEntry p_blend_shape) const {
// Fail if the blend shape index is out of range. // Fail if the blend shape index is out of range.
ERR_FAIL_INDEX_V(p_blend_shape, FT_MAX, 0.0f); 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. // Copy the blend shape values into the blend shape array.
memcpy(blend_shape_values, p_blend_shapes.ptr(), sizeof(blend_shape_values)); memcpy(blend_shape_values, p_blend_shapes.ptr(), sizeof(blend_shape_values));
} }
XRFaceTracker::XRFaceTracker() {
type = XRServer::TRACKER_FACE;
}

View File

@ -31,7 +31,7 @@
#ifndef XR_FACE_TRACKER_H #ifndef XR_FACE_TRACKER_H
#define 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. The XRFaceTracker class provides face blend shape weights.
@ -41,8 +41,8 @@
and Meta Movement standards. and Meta Movement standards.
*/ */
class XRFaceTracker : public RefCounted { class XRFaceTracker : public XRTracker {
GDCLASS(XRFaceTracker, RefCounted); GDCLASS(XRFaceTracker, XRTracker);
_THREAD_SAFE_CLASS_ _THREAD_SAFE_CLASS_
public: public:
@ -195,12 +195,16 @@ public:
FT_MAX // Maximum blend shape. FT_MAX // Maximum blend shape.
}; };
void set_tracker_type(XRServer::TrackerType p_type) override;
float get_blend_shape(BlendShapeEntry p_blend_shape) const; float get_blend_shape(BlendShapeEntry p_blend_shape) const;
void set_blend_shape(BlendShapeEntry p_blend_shape, float p_value); void set_blend_shape(BlendShapeEntry p_blend_shape, float p_value);
PackedFloat32Array get_blend_shapes() const; PackedFloat32Array get_blend_shapes() const;
void set_blend_shapes(const PackedFloat32Array &p_blend_shapes); void set_blend_shapes(const PackedFloat32Array &p_blend_shapes);
XRFaceTracker();
protected: protected:
static void _bind_methods(); static void _bind_methods();

View File

@ -30,6 +30,8 @@
#include "xr_hand_tracker.h" #include "xr_hand_tracker.h"
#include "xr_body_tracker.h"
void XRHandTracker::_bind_methods() { void XRHandTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hand", "hand"), &XRHandTracker::set_hand); ClassDB::bind_method(D_METHOD("set_hand", "hand"), &XRHandTracker::set_hand);
ClassDB::bind_method(D_METHOD("get_hand"), &XRHandTracker::get_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("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); 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::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"); 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); 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) { 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 { 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()); ERR_FAIL_INDEX_V(p_joint, HAND_JOINT_MAX, Vector3());
return hand_joint_angular_velocities[p_joint]; return hand_joint_angular_velocities[p_joint];
} }
XRHandTracker::XRHandTracker() {
type = XRServer::TRACKER_HAND;
}

View File

@ -31,10 +31,10 @@
#ifndef XR_HAND_TRACKER_H #ifndef XR_HAND_TRACKER_H
#define 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 { class XRHandTracker : public XRPositionalTracker {
GDCLASS(XRHandTracker, RefCounted); GDCLASS(XRHandTracker, XRPositionalTracker);
_THREAD_SAFE_CLASS_ _THREAD_SAFE_CLASS_
public: public:
@ -90,6 +90,9 @@ public:
HAND_JOINT_FLAG_ANGULAR_VELOCITY_VALID = 32, 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); void set_hand(Hand p_hand);
Hand get_hand() const; Hand get_hand() const;
@ -114,6 +117,8 @@ public:
void set_hand_joint_angular_velocity(HandJoint p_joint, const Vector3 &p_velocity); void set_hand_joint_angular_velocity(HandJoint p_joint, const Vector3 &p_velocity);
Vector3 get_hand_joint_angular_velocity(HandJoint p_joint) const; Vector3 get_hand_joint_angular_velocity(HandJoint p_joint) const;
XRHandTracker();
protected: protected:
static void _bind_methods(); static void _bind_methods();

View File

@ -31,23 +31,13 @@
#include "xr_positional_tracker.h" #include "xr_positional_tracker.h"
#include "core/input/input.h" #include "core/input/input.h"
#include "xr_controller_tracker.h"
void XRPositionalTracker::_bind_methods() { void XRPositionalTracker::_bind_methods() {
BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN); BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN);
BIND_ENUM_CONSTANT(TRACKER_HAND_LEFT); BIND_ENUM_CONSTANT(TRACKER_HAND_LEFT);
BIND_ENUM_CONSTANT(TRACKER_HAND_RIGHT); BIND_ENUM_CONSTANT(TRACKER_HAND_RIGHT);
BIND_ENUM_CONSTANT(TRACKER_HAND_MAX);
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");
ClassDB::bind_method(D_METHOD("get_tracker_profile"), &XRPositionalTracker::get_tracker_profile); 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); 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"))); 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) { void XRPositionalTracker::set_tracker_profile(const String &p_profile) {
if (profile != p_profile) { if (profile != p_profile) {
profile = p_profile; profile = p_profile;
@ -114,19 +76,12 @@ String XRPositionalTracker::get_tracker_profile() const {
} }
XRPositionalTracker::TrackerHand XRPositionalTracker::get_tracker_hand() const { XRPositionalTracker::TrackerHand XRPositionalTracker::get_tracker_hand() const {
return hand; return tracker_hand;
}; };
void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) { void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) {
XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_INDEX(p_hand, TRACKER_HAND_MAX);
ERR_FAIL_NULL(xr_server); tracker_hand = p_hand;
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;
};
}; };
bool XRPositionalTracker::has_pose(const StringName &p_action_name) const { 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 { Variant XRPositionalTracker::get_input(const StringName &p_action_name) const {
// Complain if this method is called on a XRPositionalTracker instance.
if (!dynamic_cast<const XRControllerTracker *>(this)) {
WARN_DEPRECATED_MSG(R"*(The "get_input()" method is deprecated, use "XRControllerTracker" instead.)*");
}
if (inputs.has(p_action_name)) { if (inputs.has(p_action_name)) {
return inputs[p_action_name]; return inputs[p_action_name];
} else { } 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) { 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<XRControllerTracker *>(this)) {
WARN_DEPRECATED_MSG(R"*(The "set_input()" method is deprecated, use "XRControllerTracker" instead.)*");
}
// XR inputs // XR inputs
bool changed;
if (inputs.has(p_action_name)) { if (inputs.has(p_action_name)) {
changed = inputs[p_action_name] != p_value; changed = inputs[p_action_name] != p_value;
} else { } 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;
};

View File

@ -34,6 +34,7 @@
#include "core/os/thread_safe.h" #include "core/os/thread_safe.h"
#include "scene/resources/mesh.h" #include "scene/resources/mesh.h"
#include "servers/xr/xr_pose.h" #include "servers/xr/xr_pose.h"
#include "servers/xr/xr_tracker.h"
#include "servers/xr_server.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. 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 { class XRPositionalTracker : public XRTracker {
GDCLASS(XRPositionalTracker, RefCounted); GDCLASS(XRPositionalTracker, XRTracker);
_THREAD_SAFE_CLASS_ _THREAD_SAFE_CLASS_
public: public:
enum TrackerHand { enum TrackerHand {
TRACKER_HAND_UNKNOWN, /* unknown or not applicable */ TRACKER_HAND_UNKNOWN, /* unknown or not applicable */
TRACKER_HAND_LEFT, /* controller is the left hand controller */ 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: protected:
XRServer::TrackerType type; // type of tracker
StringName name; // (unique) name of the tracker
String description; // description of the tracker
String profile; // this is interface dependent, for OpenXR this will be the interaction profile bound for to the tracker 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<StringName, Ref<XRPose>> poses; HashMap<StringName, Ref<XRPose>> poses;
HashMap<StringName, Variant> inputs; HashMap<StringName, Variant> inputs;
protected:
static void _bind_methods(); static void _bind_methods();
public: 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); void set_tracker_profile(const String &p_profile);
String get_tracker_profile() const; String get_tracker_profile() const;
XRPositionalTracker::TrackerHand get_tracker_hand() 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; bool has_pose(const StringName &p_action_name) const;
Ref<XRPose> get_pose(const StringName &p_action_name) const; Ref<XRPose> get_pose(const StringName &p_action_name) const;
@ -85,9 +78,6 @@ public:
Variant get_input(const StringName &p_action_name) const; Variant get_input(const StringName &p_action_name) const;
void set_input(const StringName &p_action_name, const Variant &p_value); void set_input(const StringName &p_action_name, const Variant &p_value);
XRPositionalTracker();
~XRPositionalTracker() {}
}; };
VARIANT_ENUM_CAST(XRPositionalTracker::TrackerHand); VARIANT_ENUM_CAST(XRPositionalTracker::TrackerHand);

70
servers/xr/xr_tracker.cpp Normal file
View File

@ -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;
}

61
servers/xr/xr_tracker.h Normal file
View File

@ -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

View File

@ -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<XRPositionalTracker> &p_tracker) {
add_tracker(p_tracker);
}
void XRServer::_remove_tracker_bind_compat_90645(const Ref<XRPositionalTracker> &p_tracker) {
remove_tracker(p_tracker);
}
Ref<XRPositionalTracker> 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

View File

@ -35,6 +35,7 @@
#include "xr/xr_hand_tracker.h" #include "xr/xr_hand_tracker.h"
#include "xr/xr_interface.h" #include "xr/xr_interface.h"
#include "xr/xr_positional_tracker.h" #include "xr/xr_positional_tracker.h"
#include "xr_server.compat.inc"
XRServer::XRMode XRServer::xr_mode = XRMODE_DEFAULT; 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_trackers", "tracker_types"), &XRServer::get_trackers);
ClassDB::bind_method(D_METHOD("get_tracker", "tracker_name"), &XRServer::get_tracker); 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("get_primary_interface"), &XRServer::get_primary_interface);
ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_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_CONTROLLER);
BIND_ENUM_CONSTANT(TRACKER_BASESTATION); BIND_ENUM_CONSTANT(TRACKER_BASESTATION);
BIND_ENUM_CONSTANT(TRACKER_ANCHOR); 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_ANY_KNOWN);
BIND_ENUM_CONSTANT(TRACKER_UNKNOWN); BIND_ENUM_CONSTANT(TRACKER_UNKNOWN);
BIND_ENUM_CONSTANT(TRACKER_ANY); 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_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_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("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 { double XRServer::get_world_scale() const {
@ -281,7 +258,7 @@ void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface
} }
}; };
void XRServer::add_tracker(Ref<XRPositionalTracker> p_tracker) { void XRServer::add_tracker(const Ref<XRTracker> &p_tracker) {
ERR_FAIL_COND(p_tracker.is_null()); ERR_FAIL_COND(p_tracker.is_null());
StringName tracker_name = p_tracker->get_tracker_name(); StringName tracker_name = p_tracker->get_tracker_name();
@ -297,7 +274,7 @@ void XRServer::add_tracker(Ref<XRPositionalTracker> p_tracker) {
} }
}; };
void XRServer::remove_tracker(Ref<XRPositionalTracker> p_tracker) { void XRServer::remove_tracker(const Ref<XRTracker> &p_tracker) {
ERR_FAIL_COND(p_tracker.is_null()); ERR_FAIL_COND(p_tracker.is_null());
StringName tracker_name = p_tracker->get_tracker_name(); StringName tracker_name = p_tracker->get_tracker_name();
@ -323,12 +300,12 @@ Dictionary XRServer::get_trackers(int p_tracker_types) {
return res; return res;
} }
Ref<XRPositionalTracker> XRServer::get_tracker(const StringName &p_name) const { Ref<XRTracker> XRServer::get_tracker(const StringName &p_name) const {
if (trackers.has(p_name)) { if (trackers.has(p_name)) {
return trackers[p_name]; return trackers[p_name];
} else { } else {
// tracker hasn't been registered yet, which is fine, no need to spam the error log... // tracker hasn't been registered yet, which is fine, no need to spam the error log...
return Ref<XRPositionalTracker>(); return Ref<XRTracker>();
} }
}; };
@ -382,120 +359,6 @@ PackedStringArray XRServer::get_suggested_pose_names(const StringName &p_tracker
return arr; return arr;
} }
void XRServer::add_hand_tracker(const StringName &p_tracker_name, Ref<XRHandTracker> 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<XRHandTracker> 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<XRHandTracker>();
}
return hand_trackers[p_tracker_name];
}
void XRServer::add_face_tracker(const StringName &p_tracker_name, Ref<XRFaceTracker> 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<XRFaceTracker> 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<XRFaceTracker>();
}
return face_trackers[p_tracker_name];
}
void XRServer::add_body_tracker(const StringName &p_tracker_name, Ref<XRBodyTracker> 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<XRBodyTracker> 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<XRBodyTracker>();
}
return body_trackers[p_tracker_name];
}
void XRServer::_process() { void XRServer::_process() {
// called from our main game loop before we handle physics and game logic // 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 // note that we can have multiple interfaces active if we have interfaces that purely handle tracking
@ -545,14 +408,8 @@ XRServer::XRServer() {
XRServer::~XRServer() { XRServer::~XRServer() {
primary_interface.unref(); primary_interface.unref();
while (interfaces.size() > 0) { interfaces.clear();
interfaces.remove_at(0); trackers.clear();
}
// TODO pretty sure there is a clear function or something...
while (trackers.size() > 0) {
trackers.erase(trackers.get_key_at_index(0));
}
singleton = nullptr; singleton = nullptr;
}; };

View File

@ -38,10 +38,8 @@
#include "core/variant/variant.h" #include "core/variant/variant.h"
class XRInterface; class XRInterface;
class XRTracker;
class XRPositionalTracker; class XRPositionalTracker;
class XRHandTracker;
class XRFaceTracker;
class XRBodyTracker;
/** /**
The XR server is a singleton object that gives access to the various 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_CONTROLLER = 0x02, /* tracks a controller */
TRACKER_BASESTATION = 0x04, /* tracks location of a base station */ 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_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_UNKNOWN = 0x80, /* unknown tracker */
TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */ TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */
@ -88,9 +89,6 @@ private:
Vector<Ref<XRInterface>> interfaces; Vector<Ref<XRInterface>> interfaces;
Dictionary trackers; Dictionary trackers;
Dictionary hand_trackers;
Dictionary face_trackers;
Dictionary body_trackers;
Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ Ref<XRInterface> 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(); static void _bind_methods();
#ifndef DISABLE_DEPRECATED
static void _bind_compatibility_methods();
void _add_tracker_bind_compat_90645(const Ref<XRPositionalTracker> &p_tracker);
void _remove_tracker_bind_compat_90645(const Ref<XRPositionalTracker> &p_tracker);
Ref<XRPositionalTracker> _get_tracker_bind_compat_90645(const StringName &p_name) const;
#endif
public: public:
static XRMode get_xr_mode(); static XRMode get_xr_mode();
static void set_xr_mode(XRMode p_mode); static void set_xr_mode(XRMode p_mode);
@ -174,13 +179,13 @@ public:
void set_primary_interface(const Ref<XRInterface> &p_primary_interface); void set_primary_interface(const Ref<XRInterface> &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. They are created and managed by our active AR/VR interfaces.
*/ */
void add_tracker(Ref<XRPositionalTracker> p_tracker); void add_tracker(const Ref<XRTracker> &p_tracker);
void remove_tracker(Ref<XRPositionalTracker> p_tracker); void remove_tracker(const Ref<XRTracker> &p_tracker);
Dictionary get_trackers(int p_tracker_types); Dictionary get_trackers(int p_tracker_types);
Ref<XRPositionalTracker> get_tracker(const StringName &p_name) const; Ref<XRTracker> 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. 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; 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? // 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<XRHandTracker> p_hand_tracker);
void remove_hand_tracker(const StringName &p_tracker_name);
Dictionary get_hand_trackers() const;
Ref<XRHandTracker> 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<XRFaceTracker> p_face_tracker);
void remove_face_tracker(const StringName &p_tracker_name);
Dictionary get_face_trackers() const;
Ref<XRFaceTracker> 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<XRBodyTracker> p_face_tracker);
void remove_body_tracker(const StringName &p_tracker_name);
Dictionary get_body_trackers() const;
Ref<XRBodyTracker> 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. // 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(); void _process();