mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2026-01-04 06:50:07 +01:00
Add OpenXR hand tracking demo
This commit is contained in:
5
xr/openxr_hand_tracking_demo/.gitignore
vendored
Normal file
5
xr/openxr_hand_tracking_demo/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Ignore our Android build folder, should be installed by user if needed
|
||||||
|
android/
|
||||||
|
|
||||||
|
# Ignore vendor plugin add on folder, should be installed by user if needed
|
||||||
|
addons/godotopenxrvendors/
|
||||||
159
xr/openxr_hand_tracking_demo/README.md
Normal file
159
xr/openxr_hand_tracking_demo/README.md
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
# XR Hand Tracking Demo
|
||||||
|
|
||||||
|
This is a demo showing OpenXRs hand tracking and controller tracking logic.
|
||||||
|
|
||||||
|
Language: GDScript
|
||||||
|
|
||||||
|
Renderer: Compatibility
|
||||||
|
|
||||||
|
> Note: this demo requires Godot 4.3 or later
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## How does it work?
|
||||||
|
|
||||||
|
Being able to see the players hands, and having those hands interact with elements in the environment are paramount to a good XR experience.
|
||||||
|
|
||||||
|
In this demo we look at the off the shelf logic for displaying a hand model that is automated based on either controller input or through optical tracking of the players hands.
|
||||||
|
We also implement logic that allows interaction based on input from the action map that allows the user to pick up the blocks in this demo.
|
||||||
|
|
||||||
|
The problem this poses to us is that there have been two schools of thought around what hand tracking actually means,
|
||||||
|
and depending on the XR runtime in use there may be gaps in functionality.
|
||||||
|
|
||||||
|
### Hand tracking is only for optical tracking
|
||||||
|
|
||||||
|
The first school of thought treats hand tracking as a separate system that purely focusses on optical hand tracking.
|
||||||
|
The hand tracking API in OpenXR, even if reported as supported, will only provide data if optical hand tracking is used.
|
||||||
|
|
||||||
|
This means that when controllers are used, no data is available and you as a developer have to come up with your own
|
||||||
|
solution for displaying a hand mesh and animating it according to controller input.
|
||||||
|
Note that the current version of Godot XR Tools contains a full solution for this.
|
||||||
|
|
||||||
|
Equally in this line of thought, the action map is only applicable to controller input.
|
||||||
|
You as a developer are responsible for implementing some means of gesture recognition when optical hand tracking is active.
|
||||||
|
|
||||||
|
This becomes extra nightmarish when support for both controller tracking and optical hand tracking needs to be supported in a single application.
|
||||||
|
|
||||||
|
### The unified approach
|
||||||
|
|
||||||
|
The second school of thought ignores the differences between controller tracking and optical hand tracking
|
||||||
|
and treats them as two versions of the same.
|
||||||
|
Especially with controllers like the Valve Index, or with various data gloves that are treated as controllers,
|
||||||
|
there is no discernible difference here.
|
||||||
|
|
||||||
|
The hand tracking API is mostly used for visualising the players hand with bone positions either being inferred
|
||||||
|
from controller input or matching the optical tracking.
|
||||||
|
For advanced gesture recognition you would still use this data however it is now accessible regardless of
|
||||||
|
the physical means in which this data is obtained.
|
||||||
|
|
||||||
|
At the same time, in this school of thought the action map system is seen as the primary means to gain input
|
||||||
|
and is no longer restriced to input from controllers. The XR runtime is now responsible for recognising base
|
||||||
|
gestures such as pinching and pointing resulting in inputs that can be bound in the action map.
|
||||||
|
|
||||||
|
OpenXR is moving towards this approach and this demo has been build in accordance with this however not all runtimes have been updated yet.
|
||||||
|
|
||||||
|
SteamVR has followed this approach for a long time and works out of the box, however SteamVR treats everything as controllers resulting in some short comings when a Quest is used over Meta Link or Steam Link and optical hand tracking is used.
|
||||||
|
|
||||||
|
Metas native Quest runtime on all versions of Quest now support OpenXRs "data source extension" which Godot enables when hand tracking is enabled.
|
||||||
|
However Meta does not yet support OpenXRs "hand interaction profile extension" which is required.
|
||||||
|
|
||||||
|
Meta link is still trailing behind and does not support this brave new world **yet**.
|
||||||
|
|
||||||
|
For other runtimes like Picos, HTC, Varjos, Magic Leaps, etc. may or may not yet support the required extensions.
|
||||||
|
|
||||||
|
### Conclusion
|
||||||
|
|
||||||
|
Due to the wildgrowth in capabilities in XR runtimes,
|
||||||
|
and there being no solid way to detect the full limitations of the platform you are currently on,
|
||||||
|
Godot XR Tools does not have support for the hand tracking API and purely relies on its own inferred hand positioning approach.
|
||||||
|
|
||||||
|
However with more and more runtimes adopting these new extensions any solution that targets platforms with support,
|
||||||
|
it is becoming possible to rely on the hand tracking API.
|
||||||
|
|
||||||
|
This demo project shows what that future looks like.
|
||||||
|
|
||||||
|
## Hand tracking API
|
||||||
|
|
||||||
|
As mentioned, the hand tracking API is at the center of visualising the users hand.
|
||||||
|
In Godot 4.3 we overhauled the system so the XR Interface needs to convert hand tracking data to the Godot humanoid skeleton hand bone layout.
|
||||||
|
This also means that this logic works both in WebXR, OpenXR and any other XR Interface that adds support for this feature.
|
||||||
|
|
||||||
|
Hand tracking now also makes use of the new Skeleton Modifier logic in Godot 4.3 however
|
||||||
|
the skeleton is posed in the hands local space, while positioning is provided through a XRNode3D node.
|
||||||
|
|
||||||
|
This split is applied because:
|
||||||
|
|
||||||
|
* positioning is always within the local space of the XROrigin3D node
|
||||||
|
* there are many use cases where the positioning may be ignored or modified
|
||||||
|
|
||||||
|
> Note that the trackers used for the hand tracking API are `/user/hand_tracker/left` and `/user/hand_tracker/right`.
|
||||||
|
|
||||||
|
## (Half) body Tracking API
|
||||||
|
|
||||||
|
Just an honerable mention of this, this is not part of this demo but Godot now also has support
|
||||||
|
for half and full body tracking that includes hand tracking. This functionality however is only
|
||||||
|
available on a limited number of XR runtimes.
|
||||||
|
|
||||||
|
## Action map
|
||||||
|
|
||||||
|
As mentioned, we're using the action map here for input however when optical hand tracking is used
|
||||||
|
we rely on OpenXRs hand interaction profile extension. Without support for this extension this demo
|
||||||
|
will not fully function.
|
||||||
|
|
||||||
|
This can be solved by checking that no interaction profile has been bound to our XRController3D node,
|
||||||
|
and performing our own gesture detection.
|
||||||
|
As this would greatly increase the complexity of this demo and the expectation is that this extension
|
||||||
|
will soon see wide adoption, this is left out of the demo.
|
||||||
|
|
||||||
|
> Some headsets will support the simple controller when hand tracking is enabled.
|
||||||
|
> The simple controller interaction profile doesn't support an input for grabbing.
|
||||||
|
> In this scenario you can grab the cubes using the pinch gesture
|
||||||
|
> (touch the tip of your thumb with the tip of our index finger).
|
||||||
|
|
||||||
|
We are not using the default action map and instead have created an action map specific to this use case.
|
||||||
|
|
||||||
|
There are only two actions needed for this example:
|
||||||
|
- `pose` is used to position the XRController3D nodes and mapped to the grip pose in most cases
|
||||||
|
- `pickup` is used as the input for picking up an object, and mapped accordingly.
|
||||||
|
|
||||||
|
The pickup logic itself is split into two components:
|
||||||
|
|
||||||
|
* `pickup_handler.gd/.tscn` is an Area3D node with logic that is added as a child to an XRController3D node and handles the logic for that hand to pick up objects in range.
|
||||||
|
* `pickup_able_body.gd` is a script that can be added to a RigidBody3D node to make it possible to pick up/drop that object.
|
||||||
|
|
||||||
|
> Note that the trackers used by the action map are `left_hand` and `right_hand`.
|
||||||
|
|
||||||
|
### MSFT Hand interaction extension
|
||||||
|
|
||||||
|
Microsoft introduced a hand interaction extension that Godot now supports and is configured for this project.
|
||||||
|
Several other vendors such as Meta have added support for this extension as well.
|
||||||
|
|
||||||
|
With this extension both grab gestures and pinch gestures are supported and you can thus pick up the blocks in this project by making a grab motion (making a fist).
|
||||||
|
|
||||||
|
### HTC Hand interaction extension
|
||||||
|
|
||||||
|
HTC introduced a hand interaction extension that Godot now support however this has not been implemented in this project.
|
||||||
|
This extension introduces two new trackers requiring you to change the trackers on the XRController3D node to make this work.
|
||||||
|
|
||||||
|
## Local floor reference space
|
||||||
|
|
||||||
|
A final notable element is that this demo uses the local floor reference space.
|
||||||
|
|
||||||
|
With this reference space the XR runtime will center the player on the XROrigin3D node when the user triggers the recenter logic.
|
||||||
|
The startup behavior is different between different XR runtimes, Quest will attempt to remember where you recentered last, while SteamVR tends to reset this to default.
|
||||||
|
It can thus not be guaranteed the player is in the correct spot when the demo starts.
|
||||||
|
Hence the instructions suggesting the user recenters.
|
||||||
|
|
||||||
|
## Running on PCVR
|
||||||
|
|
||||||
|
This project can be run as normal for PCVR. Ensure that an OpenXR runtime has been installed.
|
||||||
|
This project has been tested with the Oculus client and SteamVR OpenXR runtimes.
|
||||||
|
Note that Godot currently can't run using the WMR OpenXR runtime. Install SteamVR with WMR support.
|
||||||
|
|
||||||
|
## Running on standalone VR
|
||||||
|
|
||||||
|
You must install the Android build templates and OpenXR loader plugin and configure an export template for your device.
|
||||||
|
Please follow [the instructions for deploying on Android in the manual](https://docs.godotengine.org/en/stable/tutorials/xr/deploying_to_android.html).
|
||||||
|
|
||||||
BIN
xr/openxr_hand_tracking_demo/assets/gltf/LeftHandHumanoid.bin
Normal file
BIN
xr/openxr_hand_tracking_demo/assets/gltf/LeftHandHumanoid.bin
Normal file
Binary file not shown.
739
xr/openxr_hand_tracking_demo/assets/gltf/LeftHandHumanoid.gltf
Normal file
739
xr/openxr_hand_tracking_demo/assets/gltf/LeftHandHumanoid.gltf
Normal file
@@ -0,0 +1,739 @@
|
|||||||
|
{
|
||||||
|
"asset":{
|
||||||
|
"generator":"Khronos glTF Blender I/O v4.0.44",
|
||||||
|
"version":"2.0"
|
||||||
|
},
|
||||||
|
"scene":0,
|
||||||
|
"scenes":[
|
||||||
|
{
|
||||||
|
"name":"Scene",
|
||||||
|
"nodes":[
|
||||||
|
26
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nodes":[
|
||||||
|
{
|
||||||
|
"name":"LeftThumbTip",
|
||||||
|
"rotation":[
|
||||||
|
-0.001300050993449986,
|
||||||
|
-0.009501079097390175,
|
||||||
|
-0.028294457122683525,
|
||||||
|
0.9995536208152771
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
1.0000001192092896
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-2.7939677238464355e-09,
|
||||||
|
0.030749443918466568,
|
||||||
|
-2.7939677238464355e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"name":"LeftThumbDistal",
|
||||||
|
"rotation":[
|
||||||
|
-0.005640584509819746,
|
||||||
|
0.011601205915212631,
|
||||||
|
0.028976770117878914,
|
||||||
|
0.9994968771934509
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
1.0000001192092896,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
4.6566128730773926e-09,
|
||||||
|
0.04214790090918541,
|
||||||
|
1.862645149230957e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"name":"LeftThumbProximal",
|
||||||
|
"rotation":[
|
||||||
|
0.0857066959142685,
|
||||||
|
-0.027135683223605156,
|
||||||
|
0.020723098888993263,
|
||||||
|
0.9957351684570312
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0.9999998807907104
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-2.7939677238464355e-09,
|
||||||
|
0.04491649195551872,
|
||||||
|
4.656612873077393e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"name":"LeftThumbMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.09866384416818619,
|
||||||
|
0.3619273900985718,
|
||||||
|
0.3093259632587433,
|
||||||
|
0.8738372325897217
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-0.019999975338578224,
|
||||||
|
0.02717285417020321,
|
||||||
|
0.009999998845160007
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"LeftIndexTip",
|
||||||
|
"rotation":[
|
||||||
|
0.10513854771852493,
|
||||||
|
0.002554001985117793,
|
||||||
|
-0.05383634194731712,
|
||||||
|
0.9929959774017334
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-6.402842700481415e-10,
|
||||||
|
0.02712245285511017,
|
||||||
|
-1.6589183360338211e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"name":"LeftIndexDistal",
|
||||||
|
"rotation":[
|
||||||
|
0.006294804625213146,
|
||||||
|
-0.014059717766940594,
|
||||||
|
0.011407645419239998,
|
||||||
|
0.9998162984848022
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999998807907104,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-8.731149137020111e-11,
|
||||||
|
0.030106855556368828,
|
||||||
|
-1.862645149230957e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"name":"LeftIndexIntermediate",
|
||||||
|
"rotation":[
|
||||||
|
0.1859731674194336,
|
||||||
|
-0.02551458030939102,
|
||||||
|
-0.010402532294392586,
|
||||||
|
0.982168436050415
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
1.0000001192092896
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
1.1641532182693481e-09,
|
||||||
|
0.03811633959412575,
|
||||||
|
3.4924596548080444e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
6
|
||||||
|
],
|
||||||
|
"name":"LeftIndexProximal",
|
||||||
|
"rotation":[
|
||||||
|
-0.07441822439432144,
|
||||||
|
0.002075796714052558,
|
||||||
|
0.11123824119567871,
|
||||||
|
0.9910013675689697
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
4.3306158659106586e-10,
|
||||||
|
0.08036758750677109,
|
||||||
|
-2.1805135475005955e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
7
|
||||||
|
],
|
||||||
|
"name":"LeftIndexMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.0252196304500103,
|
||||||
|
2.1154794012545608e-05,
|
||||||
|
-0.0005887916195206344,
|
||||||
|
0.9996817708015442
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-0.022405147552490234,
|
||||||
|
0.02717723324894905,
|
||||||
|
-0.010000002570450306
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"LeftMiddleTip",
|
||||||
|
"rotation":[
|
||||||
|
0.1568938046693802,
|
||||||
|
0.0025405443739145994,
|
||||||
|
0.010807150974869728,
|
||||||
|
0.987553060054779
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
1.0000001192092896,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
6.366462912410498e-10,
|
||||||
|
0.028246993198990822,
|
||||||
|
4.3537511373870075e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
9
|
||||||
|
],
|
||||||
|
"name":"LeftMiddleDistal",
|
||||||
|
"rotation":[
|
||||||
|
-0.03076975606381893,
|
||||||
|
-0.001283689751289785,
|
||||||
|
-0.011195655912160873,
|
||||||
|
0.9994630217552185
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999998807907104,
|
||||||
|
1.0000001192092896,
|
||||||
|
0.9999998807907104
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
1.1095835361629725e-10,
|
||||||
|
0.03174003213644028,
|
||||||
|
1.0500116331968457e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"name":"LeftMiddleIntermediate",
|
||||||
|
"rotation":[
|
||||||
|
0.07791730761528015,
|
||||||
|
0.005997773725539446,
|
||||||
|
0.03916316106915474,
|
||||||
|
0.996172308921814
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
2.473825588822365e-10,
|
||||||
|
0.04500338435173035,
|
||||||
|
4.145476850681007e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"name":"LeftMiddleProximal",
|
||||||
|
"rotation":[
|
||||||
|
0.05410468578338623,
|
||||||
|
0.00044474273454397917,
|
||||||
|
-0.011977387592196465,
|
||||||
|
0.9984633922576904
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-1.8189894035458565e-10,
|
||||||
|
0.08046326786279678,
|
||||||
|
-2.045908331638202e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"name":"LeftMiddleMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.049977608025074005,
|
||||||
|
4.1883933590725064e-05,
|
||||||
|
-0.03585462272167206,
|
||||||
|
0.9981065392494202
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999998807907104,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-0.0035275882109999657,
|
||||||
|
0.02714575082063675,
|
||||||
|
-0.010000000707805157
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"LeftRingTip",
|
||||||
|
"rotation":[
|
||||||
|
0.13524393737316132,
|
||||||
|
-0.008499672636389732,
|
||||||
|
0.026296839118003845,
|
||||||
|
0.9904268383979797
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1.0000001192092896,
|
||||||
|
1.0000001192092896
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-3.245077095925808e-09,
|
||||||
|
0.0329010896384716,
|
||||||
|
-1.7462298274040222e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"name":"LeftRingDistal",
|
||||||
|
"rotation":[
|
||||||
|
-0.011438504792749882,
|
||||||
|
0.013675450347363949,
|
||||||
|
-0.0019264306174591184,
|
||||||
|
0.9998392462730408
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1.0000001192092896,
|
||||||
|
1.0000001192092896,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
3.2014213502407074e-10,
|
||||||
|
0.027040131390094757,
|
||||||
|
-1.7462298274040222e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"name":"LeftRingIntermediate",
|
||||||
|
"rotation":[
|
||||||
|
0.09900747239589691,
|
||||||
|
0.019192615523934364,
|
||||||
|
0.014731669798493385,
|
||||||
|
0.9947925209999084
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-3.798049874603748e-09,
|
||||||
|
0.04013120383024216,
|
||||||
|
-1.7898855730891228e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"name":"LeftRingProximal",
|
||||||
|
"rotation":[
|
||||||
|
0.001759529230184853,
|
||||||
|
-0.004247802309691906,
|
||||||
|
-0.05091992765665054,
|
||||||
|
0.9986922144889832
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
1.7316779121756554e-09,
|
||||||
|
0.0739438533782959,
|
||||||
|
8.585629984736443e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"name":"LeftRingMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.018085606396198273,
|
||||||
|
1.561214230605401e-05,
|
||||||
|
-0.07119491696357727,
|
||||||
|
0.9972984790802002
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999998807907104,
|
||||||
|
0.9999999403953552,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
0.013099989853799343,
|
||||||
|
0.027118019759655,
|
||||||
|
-0.010000001639127731
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"LeftLittleTip",
|
||||||
|
"rotation":[
|
||||||
|
0.03595229610800743,
|
||||||
|
-0.020332874730229378,
|
||||||
|
0.013369254767894745,
|
||||||
|
0.9990572333335876
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999997615814209,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-5.820766091346741e-10,
|
||||||
|
0.01958998665213585,
|
||||||
|
8.381903171539307e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"name":"LeftLittleDistal",
|
||||||
|
"rotation":[
|
||||||
|
0.01741550862789154,
|
||||||
|
0.014375297352671623,
|
||||||
|
-0.012779458425939083,
|
||||||
|
0.9996633529663086
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-1.04046193882823e-09,
|
||||||
|
0.01730157621204853,
|
||||||
|
3.14321368932724e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"name":"LeftLittleIntermediate",
|
||||||
|
"rotation":[
|
||||||
|
0.1067298874258995,
|
||||||
|
0.03360109031200409,
|
||||||
|
0.04032363370060921,
|
||||||
|
0.9929016828536987
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
2.0718289306387305e-09,
|
||||||
|
0.033123549073934555,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"name":"LeftLittleProximal",
|
||||||
|
"rotation":[
|
||||||
|
0.050176676362752914,
|
||||||
|
-0.0007295551477000117,
|
||||||
|
-0.08933921158313751,
|
||||||
|
0.9947363138198853
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
3.3651303965598345e-10,
|
||||||
|
0.06571119278669357,
|
||||||
|
-3.637978807091713e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"name":"LeftLittleMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.028447696939110756,
|
||||||
|
2.468071943440009e-05,
|
||||||
|
-0.09176953136920929,
|
||||||
|
0.9953738451004028
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999999403953552,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
0.029999960213899612,
|
||||||
|
0.027089649811387062,
|
||||||
|
8.651588889740935e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
3,
|
||||||
|
8,
|
||||||
|
13,
|
||||||
|
18,
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"name":"LeftHand",
|
||||||
|
"rotation":[
|
||||||
|
-0.4995875358581543,
|
||||||
|
0.5004213452339172,
|
||||||
|
-0.4995783269405365,
|
||||||
|
0.5004121661186218
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999997615814209,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
3.8642522071086205e-08,
|
||||||
|
-1.8697472114581615e-05,
|
||||||
|
0.027175573632121086
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh":0,
|
||||||
|
"name":"LeftHandHumanoidMesh",
|
||||||
|
"skin":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
25,
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"name":"LeftHandHumanoid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials":[
|
||||||
|
{
|
||||||
|
"doubleSided":true,
|
||||||
|
"name":"Hand",
|
||||||
|
"pbrMetallicRoughness":{
|
||||||
|
"baseColorTexture":{
|
||||||
|
"index":0
|
||||||
|
},
|
||||||
|
"metallicFactor":0,
|
||||||
|
"roughnessFactor":0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes":[
|
||||||
|
{
|
||||||
|
"name":"LeftHandHumanoid",
|
||||||
|
"primitives":[
|
||||||
|
{
|
||||||
|
"attributes":{
|
||||||
|
"POSITION":0,
|
||||||
|
"NORMAL":1,
|
||||||
|
"TEXCOORD_0":2,
|
||||||
|
"JOINTS_0":3,
|
||||||
|
"WEIGHTS_0":4
|
||||||
|
},
|
||||||
|
"indices":5,
|
||||||
|
"material":0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"textures":[
|
||||||
|
{
|
||||||
|
"sampler":0,
|
||||||
|
"source":0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"images":[
|
||||||
|
{
|
||||||
|
"mimeType":"image/png",
|
||||||
|
"name":"hand",
|
||||||
|
"uri":"hand.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"skins":[
|
||||||
|
{
|
||||||
|
"inverseBindMatrices":6,
|
||||||
|
"joints":[
|
||||||
|
24,
|
||||||
|
3,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
7,
|
||||||
|
6,
|
||||||
|
5,
|
||||||
|
4,
|
||||||
|
13,
|
||||||
|
12,
|
||||||
|
11,
|
||||||
|
10,
|
||||||
|
9,
|
||||||
|
18,
|
||||||
|
17,
|
||||||
|
16,
|
||||||
|
15,
|
||||||
|
14,
|
||||||
|
23,
|
||||||
|
22,
|
||||||
|
21,
|
||||||
|
20,
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"name":"LeftHandHumanoid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors":[
|
||||||
|
{
|
||||||
|
"bufferView":0,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":603,
|
||||||
|
"max":[
|
||||||
|
0.03515051305294037,
|
||||||
|
0.09001174569129944,
|
||||||
|
0.02576880156993866
|
||||||
|
],
|
||||||
|
"min":[
|
||||||
|
-0.029946302995085716,
|
||||||
|
-0.06838366389274597,
|
||||||
|
-0.18542321026325226
|
||||||
|
],
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":1,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":603,
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":2,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":603,
|
||||||
|
"type":"VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":3,
|
||||||
|
"componentType":5121,
|
||||||
|
"count":603,
|
||||||
|
"type":"VEC4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":4,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":603,
|
||||||
|
"type":"VEC4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":5,
|
||||||
|
"componentType":5123,
|
||||||
|
"count":2814,
|
||||||
|
"type":"SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":6,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":25,
|
||||||
|
"type":"MAT4"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews":[
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":7236,
|
||||||
|
"byteOffset":0,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":7236,
|
||||||
|
"byteOffset":7236,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":4824,
|
||||||
|
"byteOffset":14472,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":2412,
|
||||||
|
"byteOffset":19296,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":9648,
|
||||||
|
"byteOffset":21708,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":5628,
|
||||||
|
"byteOffset":31356,
|
||||||
|
"target":34963
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":1600,
|
||||||
|
"byteOffset":36984
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"samplers":[
|
||||||
|
{
|
||||||
|
"magFilter":9729,
|
||||||
|
"minFilter":9987
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers":[
|
||||||
|
{
|
||||||
|
"byteLength":38584,
|
||||||
|
"uri":"LeftHandHumanoid.bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://d22k0sp2hinew"
|
||||||
|
path="res://.godot/imported/LeftHandHumanoid.gltf-219698e659d03b53d9439b731eba1dad.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/gltf/LeftHandHumanoid.gltf"
|
||||||
|
dest_files=["res://.godot/imported/LeftHandHumanoid.gltf-219698e659d03b53d9439b731eba1dad.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
_subresources={}
|
||||||
|
fbx/importer=0
|
||||||
|
fbx/allow_geometry_helper_nodes=false
|
||||||
|
fbx/embedded_image_handling=1
|
||||||
|
gltf/naming_version=1
|
||||||
|
gltf/embedded_image_handling=1
|
||||||
BIN
xr/openxr_hand_tracking_demo/assets/gltf/RightHandHumanoid.bin
Normal file
BIN
xr/openxr_hand_tracking_demo/assets/gltf/RightHandHumanoid.bin
Normal file
Binary file not shown.
744
xr/openxr_hand_tracking_demo/assets/gltf/RightHandHumanoid.gltf
Normal file
744
xr/openxr_hand_tracking_demo/assets/gltf/RightHandHumanoid.gltf
Normal file
@@ -0,0 +1,744 @@
|
|||||||
|
{
|
||||||
|
"asset":{
|
||||||
|
"generator":"Khronos glTF Blender I/O v4.0.44",
|
||||||
|
"version":"2.0"
|
||||||
|
},
|
||||||
|
"scene":0,
|
||||||
|
"scenes":[
|
||||||
|
{
|
||||||
|
"name":"Scene",
|
||||||
|
"nodes":[
|
||||||
|
26
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nodes":[
|
||||||
|
{
|
||||||
|
"name":"RightThumbTip",
|
||||||
|
"rotation":[
|
||||||
|
-0.0015842723660171032,
|
||||||
|
0.01954343169927597,
|
||||||
|
0.028279954567551613,
|
||||||
|
0.9994077682495117
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
1.0000001192092896
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
2.7939677238464355e-09,
|
||||||
|
0.030749443918466568,
|
||||||
|
-2.7939677238464355e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"name":"RightThumbDistal",
|
||||||
|
"rotation":[
|
||||||
|
-0.005640584509819746,
|
||||||
|
-0.011601205915212631,
|
||||||
|
-0.028976770117878914,
|
||||||
|
0.9994968771934509
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
1.0000001192092896,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-4.6566128730773926e-09,
|
||||||
|
0.04214790090918541,
|
||||||
|
1.862645149230957e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"name":"RightThumbProximal",
|
||||||
|
"rotation":[
|
||||||
|
0.0857066959142685,
|
||||||
|
0.027135683223605156,
|
||||||
|
-0.020723098888993263,
|
||||||
|
0.9957351684570312
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0.9999998807907104
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
2.7939677238464355e-09,
|
||||||
|
0.04491649195551872,
|
||||||
|
4.656612873077393e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"name":"RightThumbMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.09866384416818619,
|
||||||
|
-0.3619273900985718,
|
||||||
|
-0.3093259632587433,
|
||||||
|
0.8738372325897217
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
0.019999975338578224,
|
||||||
|
0.02717285417020321,
|
||||||
|
0.009999998845160007
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"RightIndexTip",
|
||||||
|
"rotation":[
|
||||||
|
0.10500194132328033,
|
||||||
|
-0.00039221683982759714,
|
||||||
|
0.0540827140212059,
|
||||||
|
0.9930002689361572
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1.0000001192092896,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
9.89530235528946e-10,
|
||||||
|
0.027121681720018387,
|
||||||
|
-1.3969838619232178e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"name":"RightIndexDistal",
|
||||||
|
"rotation":[
|
||||||
|
0.006300266366451979,
|
||||||
|
0.014137149788439274,
|
||||||
|
-0.011408609338104725,
|
||||||
|
0.9998151659965515
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999998807907104,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
8.731149137020111e-11,
|
||||||
|
0.030106855556368828,
|
||||||
|
-1.862645149230957e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
5
|
||||||
|
],
|
||||||
|
"name":"RightIndexIntermediate",
|
||||||
|
"rotation":[
|
||||||
|
0.1859731674194336,
|
||||||
|
0.02551458030939102,
|
||||||
|
0.010402532294392586,
|
||||||
|
0.982168436050415
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
1.0000001192092896
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-1.1641532182693481e-09,
|
||||||
|
0.03811633959412575,
|
||||||
|
3.4924596548080444e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
6
|
||||||
|
],
|
||||||
|
"name":"RightIndexProximal",
|
||||||
|
"rotation":[
|
||||||
|
-0.07441822439432144,
|
||||||
|
-0.002075796714052558,
|
||||||
|
-0.11123824119567871,
|
||||||
|
0.9910013675689697
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-4.3306158659106586e-10,
|
||||||
|
0.08036758750677109,
|
||||||
|
-2.1805135475005955e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
7
|
||||||
|
],
|
||||||
|
"name":"RightIndexMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.0252196304500103,
|
||||||
|
-2.1154794012545608e-05,
|
||||||
|
0.0005887916195206344,
|
||||||
|
0.9996817708015442
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
0.022405147552490234,
|
||||||
|
0.02717723324894905,
|
||||||
|
-0.010000002570450306
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"RightMiddleTip",
|
||||||
|
"rotation":[
|
||||||
|
0.1537046879529953,
|
||||||
|
0.001326742465607822,
|
||||||
|
-0.011463530361652374,
|
||||||
|
0.9880494475364685
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999999403953552,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
1.0477378964424133e-09,
|
||||||
|
0.028247453272342682,
|
||||||
|
1.4370016288012266e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
9
|
||||||
|
],
|
||||||
|
"name":"RightMiddleDistal",
|
||||||
|
"rotation":[
|
||||||
|
-0.030728844925761223,
|
||||||
|
-0.0027318676002323627,
|
||||||
|
0.01131731178611517,
|
||||||
|
0.999459981918335
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
1.4370016288012266e-10,
|
||||||
|
0.03174003213644028,
|
||||||
|
1.0595613275654614e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"name":"RightMiddleIntermediate",
|
||||||
|
"rotation":[
|
||||||
|
0.07791730761528015,
|
||||||
|
-0.005997773725539446,
|
||||||
|
-0.03916317597031593,
|
||||||
|
0.996172308921814
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-2.473825588822365e-10,
|
||||||
|
0.04500338435173035,
|
||||||
|
4.145476850681007e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"name":"RightMiddleProximal",
|
||||||
|
"rotation":[
|
||||||
|
0.05410468578338623,
|
||||||
|
-0.00044474273454397917,
|
||||||
|
0.011977387592196465,
|
||||||
|
0.9984633922576904
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
1.8189894035458565e-10,
|
||||||
|
0.08046326786279678,
|
||||||
|
-2.045908331638202e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"name":"RightMiddleMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.049977608025074005,
|
||||||
|
-4.1883933590725064e-05,
|
||||||
|
0.03585462272167206,
|
||||||
|
0.9981065392494202
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999998807907104,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
0.0035275882109999657,
|
||||||
|
0.02714575082063675,
|
||||||
|
-0.010000000707805157
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"RightRingTip",
|
||||||
|
"rotation":[
|
||||||
|
0.13524393737316132,
|
||||||
|
0.008499672636389732,
|
||||||
|
-0.026296839118003845,
|
||||||
|
0.9904268383979797
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1.0000001192092896,
|
||||||
|
1.0000001192092896
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
3.245077095925808e-09,
|
||||||
|
0.0329010896384716,
|
||||||
|
-1.7462298274040222e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"name":"RightRingDistal",
|
||||||
|
"rotation":[
|
||||||
|
-0.011438504792749882,
|
||||||
|
-0.013675450347363949,
|
||||||
|
0.0019264306174591184,
|
||||||
|
0.9998392462730408
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1.0000001192092896,
|
||||||
|
1.0000001192092896,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-3.2014213502407074e-10,
|
||||||
|
0.027040131390094757,
|
||||||
|
-1.7462298274040222e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
15
|
||||||
|
],
|
||||||
|
"name":"RightRingIntermediate",
|
||||||
|
"rotation":[
|
||||||
|
0.09900747239589691,
|
||||||
|
-0.019192615523934364,
|
||||||
|
-0.014731669798493385,
|
||||||
|
0.9947925209999084
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
3.798049874603748e-09,
|
||||||
|
0.04013120383024216,
|
||||||
|
-1.7898855730891228e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
16
|
||||||
|
],
|
||||||
|
"name":"RightRingProximal",
|
||||||
|
"rotation":[
|
||||||
|
0.001759529230184853,
|
||||||
|
0.004247802309691906,
|
||||||
|
0.05091992765665054,
|
||||||
|
0.9986922144889832
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-1.7316779121756554e-09,
|
||||||
|
0.0739438533782959,
|
||||||
|
8.585629984736443e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
17
|
||||||
|
],
|
||||||
|
"name":"RightRingMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.018085606396198273,
|
||||||
|
-1.561214230605401e-05,
|
||||||
|
0.07119491696357727,
|
||||||
|
0.9972984790802002
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999998807907104,
|
||||||
|
0.9999999403953552,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-0.013099989853799343,
|
||||||
|
0.027118019759655,
|
||||||
|
-0.010000001639127731
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"RightLittleTip",
|
||||||
|
"rotation":[
|
||||||
|
0.03595229610800743,
|
||||||
|
0.020332874730229378,
|
||||||
|
-0.013369254767894745,
|
||||||
|
0.9990572333335876
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999997615814209,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
5.820766091346741e-10,
|
||||||
|
0.01958998665213585,
|
||||||
|
8.381903171539307e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"name":"RightLittleDistal",
|
||||||
|
"rotation":[
|
||||||
|
0.01741550862789154,
|
||||||
|
-0.014375297352671623,
|
||||||
|
0.012779458425939083,
|
||||||
|
0.9996633529663086
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
1.04046193882823e-09,
|
||||||
|
0.01730157621204853,
|
||||||
|
3.14321368932724e-09
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
20
|
||||||
|
],
|
||||||
|
"name":"RightLittleIntermediate",
|
||||||
|
"rotation":[
|
||||||
|
0.1067298874258995,
|
||||||
|
-0.03360109031200409,
|
||||||
|
-0.04032363370060921,
|
||||||
|
0.9929016828536987
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
1,
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-2.0718289306387305e-09,
|
||||||
|
0.033123549073934555,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"name":"RightLittleProximal",
|
||||||
|
"rotation":[
|
||||||
|
0.050176676362752914,
|
||||||
|
0.0007295551477000117,
|
||||||
|
0.08933921158313751,
|
||||||
|
0.9947363138198853
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-3.3651303965598345e-10,
|
||||||
|
0.06571119278669357,
|
||||||
|
-3.637978807091713e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
22
|
||||||
|
],
|
||||||
|
"name":"RightLittleMetacarpal",
|
||||||
|
"rotation":[
|
||||||
|
-0.028447696939110756,
|
||||||
|
-2.468071943440009e-05,
|
||||||
|
0.09176953136920929,
|
||||||
|
0.9953738451004028
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999999403953552,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-0.029999960213899612,
|
||||||
|
0.027089649811387062,
|
||||||
|
8.651588889740935e-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
3,
|
||||||
|
8,
|
||||||
|
13,
|
||||||
|
18,
|
||||||
|
23
|
||||||
|
],
|
||||||
|
"name":"RightHand",
|
||||||
|
"rotation":[
|
||||||
|
-0.4995875358581543,
|
||||||
|
-0.5004213452339172,
|
||||||
|
0.4995783269405365,
|
||||||
|
0.5004121661186218
|
||||||
|
],
|
||||||
|
"scale":[
|
||||||
|
0.9999999403953552,
|
||||||
|
0.9999997615814209,
|
||||||
|
0.9999999403953552
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
-3.8642522071086205e-08,
|
||||||
|
-1.8697472114581615e-05,
|
||||||
|
0.027175573632121086
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh":0,
|
||||||
|
"name":"RightHandHumanoidMesh",
|
||||||
|
"skin":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children":[
|
||||||
|
25,
|
||||||
|
24
|
||||||
|
],
|
||||||
|
"name":"RightHandHumanoid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials":[
|
||||||
|
{
|
||||||
|
"doubleSided":true,
|
||||||
|
"name":"Hand",
|
||||||
|
"pbrMetallicRoughness":{
|
||||||
|
"baseColorTexture":{
|
||||||
|
"index":0
|
||||||
|
},
|
||||||
|
"metallicFactor":0,
|
||||||
|
"roughnessFactor":0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes":[
|
||||||
|
{
|
||||||
|
"name":"RightHandHumanoid",
|
||||||
|
"primitives":[
|
||||||
|
{
|
||||||
|
"attributes":{
|
||||||
|
"POSITION":0,
|
||||||
|
"NORMAL":1,
|
||||||
|
"TEXCOORD_0":2,
|
||||||
|
"JOINTS_0":3,
|
||||||
|
"WEIGHTS_0":4
|
||||||
|
},
|
||||||
|
"indices":5,
|
||||||
|
"material":0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"textures":[
|
||||||
|
{
|
||||||
|
"sampler":0,
|
||||||
|
"source":0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"images":[
|
||||||
|
{
|
||||||
|
"mimeType":"image/png",
|
||||||
|
"name":"hand",
|
||||||
|
"uri":"hand.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"skins":[
|
||||||
|
{
|
||||||
|
"inverseBindMatrices":6,
|
||||||
|
"joints":[
|
||||||
|
24,
|
||||||
|
3,
|
||||||
|
2,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
7,
|
||||||
|
6,
|
||||||
|
5,
|
||||||
|
4,
|
||||||
|
13,
|
||||||
|
12,
|
||||||
|
11,
|
||||||
|
10,
|
||||||
|
9,
|
||||||
|
18,
|
||||||
|
17,
|
||||||
|
16,
|
||||||
|
15,
|
||||||
|
14,
|
||||||
|
23,
|
||||||
|
22,
|
||||||
|
21,
|
||||||
|
20,
|
||||||
|
19
|
||||||
|
],
|
||||||
|
"name":"RightHandHumanoid"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors":[
|
||||||
|
{
|
||||||
|
"bufferView":0,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":603,
|
||||||
|
"max":[
|
||||||
|
0.02935725450515747,
|
||||||
|
0.09001174569129944,
|
||||||
|
0.025806419551372528
|
||||||
|
],
|
||||||
|
"min":[
|
||||||
|
-0.035739559680223465,
|
||||||
|
-0.06838366389274597,
|
||||||
|
-0.18542321026325226
|
||||||
|
],
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":1,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":603,
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":2,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":603,
|
||||||
|
"type":"VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":3,
|
||||||
|
"componentType":5121,
|
||||||
|
"count":603,
|
||||||
|
"type":"VEC4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":4,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":603,
|
||||||
|
"type":"VEC4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":5,
|
||||||
|
"componentType":5123,
|
||||||
|
"count":2814,
|
||||||
|
"type":"SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":6,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":25,
|
||||||
|
"type":"MAT4"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews":[
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":7236,
|
||||||
|
"byteOffset":0,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":7236,
|
||||||
|
"byteOffset":7236,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":4824,
|
||||||
|
"byteOffset":14472,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":2412,
|
||||||
|
"byteOffset":19296,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":9648,
|
||||||
|
"byteOffset":21708,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":5628,
|
||||||
|
"byteOffset":31356,
|
||||||
|
"target":34963
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":1600,
|
||||||
|
"byteOffset":36984
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"samplers":[
|
||||||
|
{
|
||||||
|
"magFilter":9729,
|
||||||
|
"minFilter":9987
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers":[
|
||||||
|
{
|
||||||
|
"byteLength":38584,
|
||||||
|
"uri":"RightHandHumanoid.bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://dlswhmq6s52gu"
|
||||||
|
path="res://.godot/imported/RightHandHumanoid.gltf-9b0df2ce88fbae3fc911bc06520ecfc9.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/gltf/RightHandHumanoid.gltf"
|
||||||
|
dest_files=["res://.godot/imported/RightHandHumanoid.gltf-9b0df2ce88fbae3fc911bc06520ecfc9.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
_subresources={}
|
||||||
|
fbx/importer=0
|
||||||
|
fbx/allow_geometry_helper_nodes=false
|
||||||
|
fbx/embedded_image_handling=1
|
||||||
|
gltf/naming_version=1
|
||||||
|
gltf/embedded_image_handling=1
|
||||||
BIN
xr/openxr_hand_tracking_demo/assets/gltf/hand.png
Normal file
BIN
xr/openxr_hand_tracking_demo/assets/gltf/hand.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 283 KiB |
36
xr/openxr_hand_tracking_demo/assets/gltf/hand.png.import
Normal file
36
xr/openxr_hand_tracking_demo/assets/gltf/hand.png.import
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cblg6srneyvvs"
|
||||||
|
path.s3tc="res://.godot/imported/hand.png-a9641443c18f421b63decbe9f5ce13e4.s3tc.ctex"
|
||||||
|
path.etc2="res://.godot/imported/hand.png-a9641443c18f421b63decbe9f5ce13e4.etc2.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/gltf/hand.png"
|
||||||
|
dest_files=["res://.godot/imported/hand.png-a9641443c18f421b63decbe9f5ce13e4.s3tc.ctex", "res://.godot/imported/hand.png-a9641443c18f421b63decbe9f5ce13e4.etc2.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
BIN
xr/openxr_hand_tracking_demo/assets/images/pattern.png
Normal file
BIN
xr/openxr_hand_tracking_demo/assets/images/pattern.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,36 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b1waowk6l76ap"
|
||||||
|
path.s3tc="res://.godot/imported/pattern.png-4d94aeab07bbe0313c1636ed9890ceae.s3tc.ctex"
|
||||||
|
path.etc2="res://.godot/imported/pattern.png-4d94aeab07bbe0313c1636ed9890ceae.etc2.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/images/pattern.png"
|
||||||
|
dest_files=["res://.godot/imported/pattern.png-4d94aeab07bbe0313c1636ed9890ceae.s3tc.ctex", "res://.godot/imported/pattern.png-4d94aeab07bbe0313c1636ed9890ceae.etc2.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
53
xr/openxr_hand_tracking_demo/hand_info.gd
Normal file
53
xr/openxr_hand_tracking_demo/hand_info.gd
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export_enum("Left", "Right") var hand : int = 0
|
||||||
|
|
||||||
|
|
||||||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
func _process(delta):
|
||||||
|
var text = ""
|
||||||
|
|
||||||
|
if hand == 0:
|
||||||
|
text += "Left hand\n"
|
||||||
|
else:
|
||||||
|
text += "Right hand\n"
|
||||||
|
|
||||||
|
var controller_tracker : XRPositionalTracker = XRServer.get_tracker("left_hand" if hand == 0 else "right_hand")
|
||||||
|
if controller_tracker:
|
||||||
|
var profile = controller_tracker.profile.replace("/interaction_profiles/", "").replace("/", " ")
|
||||||
|
text += "\nProfile: " + profile + "\n"
|
||||||
|
|
||||||
|
var pose : XRPose = controller_tracker.get_pose("pose")
|
||||||
|
if pose:
|
||||||
|
if pose.tracking_confidence == XRPose.XR_TRACKING_CONFIDENCE_NONE:
|
||||||
|
text += "- No tracking data\n"
|
||||||
|
elif pose.tracking_confidence == XRPose.XR_TRACKING_CONFIDENCE_LOW:
|
||||||
|
text += "- Low confidence tracking data\n"
|
||||||
|
elif pose.tracking_confidence == XRPose.XR_TRACKING_CONFIDENCE_HIGH:
|
||||||
|
text += "- High confidence tracking data\n"
|
||||||
|
else:
|
||||||
|
text += "- Unknown tracking data %d \n" % [ pose.tracking_confidence ]
|
||||||
|
else:
|
||||||
|
text += "- No pose data\n"
|
||||||
|
else:
|
||||||
|
text += "\nNo controller tracker found!\n"
|
||||||
|
|
||||||
|
var hand_tracker : XRHandTracker = XRServer.get_tracker("/user/hand_tracker/left" if hand == 0 else "/user/hand_tracker/right")
|
||||||
|
if hand_tracker:
|
||||||
|
text += "\nHand tracker found\n"
|
||||||
|
|
||||||
|
if hand_tracker.has_tracking_data:
|
||||||
|
if hand_tracker.hand_tracking_source == XRHandTracker.HAND_TRACKING_SOURCE_UNKNOWN:
|
||||||
|
text += "- Source: unknown\n"
|
||||||
|
elif hand_tracker.hand_tracking_source == XRHandTracker.HAND_TRACKING_SOURCE_UNOBSTRUCTED:
|
||||||
|
text += "- Source: optical hand tracking\n"
|
||||||
|
elif hand_tracker.hand_tracking_source == XRHandTracker.HAND_TRACKING_SOURCE_CONTROLLER:
|
||||||
|
text += "- Source: inferred from controller\n"
|
||||||
|
else:
|
||||||
|
text += "- Source: %d\n" % [ hand_tracker.hand_tracking_source ]
|
||||||
|
else:
|
||||||
|
text += "- No tracking data\n"
|
||||||
|
else:
|
||||||
|
text += "\nNo hand tracker found!\n"
|
||||||
|
|
||||||
|
$Info.text = text
|
||||||
17
xr/openxr_hand_tracking_demo/hand_info.tscn
Normal file
17
xr/openxr_hand_tracking_demo/hand_info.tscn
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://dtabh705qyufu"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://hand_info.gd" id="1_kp65y"]
|
||||||
|
|
||||||
|
[node name="HandInfo" type="Node3D"]
|
||||||
|
script = ExtResource("1_kp65y")
|
||||||
|
|
||||||
|
[node name="Info" type="Label3D" parent="."]
|
||||||
|
pixel_size = 0.0015
|
||||||
|
text = "Hand info
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.
|
||||||
|
."
|
||||||
|
horizontal_alignment = 0
|
||||||
|
vertical_alignment = 2
|
||||||
|
autowrap_mode = 3
|
||||||
1
xr/openxr_hand_tracking_demo/icon.svg
Normal file
1
xr/openxr_hand_tracking_demo/icon.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 950 B |
37
xr/openxr_hand_tracking_demo/icon.svg.import
Normal file
37
xr/openxr_hand_tracking_demo/icon.svg.import
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dtetda3s8m6po"
|
||||||
|
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
128
xr/openxr_hand_tracking_demo/main.tscn
Normal file
128
xr/openxr_hand_tracking_demo/main.tscn
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
[gd_scene load_steps=14 format=3 uid="uid://br3bss6kac8pa"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://d22k0sp2hinew" path="res://assets/gltf/LeftHandHumanoid.gltf" id="2_3hxem"]
|
||||||
|
[ext_resource type="Script" path="res://start_vr.gd" id="2_5rtkn"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dlswhmq6s52gu" path="res://assets/gltf/RightHandHumanoid.gltf" id="3_oifi1"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://byif52d1xkl3u" path="res://pickup/pickup_handler.tscn" id="3_sg1io"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b1waowk6l76ap" path="res://assets/images/pattern.png" id="4_3x0ea"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dtabh705qyufu" path="res://hand_info.tscn" id="5_wlhtu"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://hanl00aqvu7u" path="res://objects/table.tscn" id="6_rfmma"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cerkxyasq8t8b" path="res://objects/box.tscn" id="7_6sqt7"]
|
||||||
|
|
||||||
|
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_eyx45"]
|
||||||
|
sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
|
||||||
|
ground_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
|
||||||
|
|
||||||
|
[sub_resource type="Sky" id="Sky_tsis2"]
|
||||||
|
sky_material = SubResource("ProceduralSkyMaterial_eyx45")
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id="Environment_0xu52"]
|
||||||
|
background_mode = 2
|
||||||
|
sky = SubResource("Sky_tsis2")
|
||||||
|
tonemap_mode = 2
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dxr1t"]
|
||||||
|
albedo_color = Color(0.187808, 0.607643, 0.279312, 1)
|
||||||
|
albedo_texture = ExtResource("4_3x0ea")
|
||||||
|
uv1_scale = Vector3(100, 100, 100)
|
||||||
|
|
||||||
|
[sub_resource type="PlaneMesh" id="PlaneMesh_6hhse"]
|
||||||
|
material = SubResource("StandardMaterial3D_dxr1t")
|
||||||
|
size = Vector2(1000, 1000)
|
||||||
|
subdivide_width = 10
|
||||||
|
subdivide_depth = 10
|
||||||
|
|
||||||
|
[node name="Main" type="Node3D"]
|
||||||
|
|
||||||
|
[node name="StartVR" type="Node3D" parent="."]
|
||||||
|
script = ExtResource("2_5rtkn")
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||||
|
environment = SubResource("Environment_0xu52")
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||||
|
transform = Transform3D(0.397904, -0.794516, 0.458712, 0, 0.499998, 0.866026, -0.917427, -0.344595, 0.198951, 0, 5, 0)
|
||||||
|
directional_shadow_max_distance = 10.0
|
||||||
|
|
||||||
|
[node name="Floor" type="MeshInstance3D" parent="."]
|
||||||
|
mesh = SubResource("PlaneMesh_6hhse")
|
||||||
|
|
||||||
|
[node name="RecenterInfo" type="Label3D" parent="Floor"]
|
||||||
|
transform = Transform3D(0.59873, 0, 0.800951, 0, 1, 0, -0.800951, 0, 0.59873, -1.76283, 1.50033, -0.380399)
|
||||||
|
pixel_size = 0.003
|
||||||
|
text = "If you are not facing the table,
|
||||||
|
recenter your headset.
|
||||||
|
|
||||||
|
On Quest, hold the Meta button
|
||||||
|
on your right controller
|
||||||
|
for several seconds
|
||||||
|
|
||||||
|
In SteamVR, open the menu and
|
||||||
|
select recenter and follow
|
||||||
|
instructions"
|
||||||
|
|
||||||
|
[node name="Table" parent="." instance=ExtResource("6_rfmma")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5)
|
||||||
|
|
||||||
|
[node name="Box01" parent="Table" instance=ExtResource("7_6sqt7")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.941084, 0)
|
||||||
|
|
||||||
|
[node name="Box02" parent="Table" instance=ExtResource("7_6sqt7")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.13752, 0.941084, 0)
|
||||||
|
|
||||||
|
[node name="Box03" parent="Table" instance=ExtResource("7_6sqt7")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0746718, 1.06282, 0)
|
||||||
|
|
||||||
|
[node name="LeftHandInfo" parent="Table" instance=ExtResource("5_wlhtu")]
|
||||||
|
transform = Transform3D(0.939693, -0.085635, 0.331126, 0, 0.968147, 0.25038, -0.34202, -0.23528, 0.909761, -0.713026, 0.8718, -0.309953)
|
||||||
|
|
||||||
|
[node name="RightHandInfo" parent="Table" instance=ExtResource("5_wlhtu")]
|
||||||
|
transform = Transform3D(0.939693, 0.085635, -0.331126, 0, 0.968147, 0.25038, 0.34202, -0.23528, 0.909761, 0.278022, 0.8718, -0.381943)
|
||||||
|
hand = 1
|
||||||
|
|
||||||
|
[node name="XROrigin3D" type="XROrigin3D" parent="."]
|
||||||
|
|
||||||
|
[node name="XRCamera3D" type="XRCamera3D" parent="XROrigin3D"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.7, 0)
|
||||||
|
|
||||||
|
[node name="LeftHandController" type="XRController3D" parent="XROrigin3D"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 1, -0.5)
|
||||||
|
tracker = &"left_hand"
|
||||||
|
pose = &"pose"
|
||||||
|
show_when_tracked = true
|
||||||
|
|
||||||
|
[node name="PickupHandler" parent="XROrigin3D/LeftHandController" instance=ExtResource("3_sg1io")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.05, 0, 0)
|
||||||
|
pickup_action = "pickup"
|
||||||
|
|
||||||
|
[node name="RightHandController" type="XRController3D" parent="XROrigin3D"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 1, -0.5)
|
||||||
|
tracker = &"right_hand"
|
||||||
|
pose = &"pose"
|
||||||
|
show_when_tracked = true
|
||||||
|
|
||||||
|
[node name="PickupHandler" parent="XROrigin3D/RightHandController" instance=ExtResource("3_sg1io")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.05, 0, 0)
|
||||||
|
pickup_action = "pickup"
|
||||||
|
|
||||||
|
[node name="LeftHandMesh" type="XRNode3D" parent="XROrigin3D"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 1, -0.5)
|
||||||
|
tracker = &"/user/hand_tracker/left"
|
||||||
|
show_when_tracked = true
|
||||||
|
|
||||||
|
[node name="LeftHandHumanoid2" parent="XROrigin3D/LeftHandMesh" instance=ExtResource("2_3hxem")]
|
||||||
|
|
||||||
|
[node name="XRHandModifier3D" type="XRHandModifier3D" parent="XROrigin3D/LeftHandMesh/LeftHandHumanoid2/LeftHandHumanoid/Skeleton3D" index="1"]
|
||||||
|
|
||||||
|
[node name="RightHandMesh" type="XRNode3D" parent="XROrigin3D"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 1, -0.5)
|
||||||
|
tracker = &"/user/hand_tracker/right"
|
||||||
|
show_when_tracked = true
|
||||||
|
|
||||||
|
[node name="RightHandHumanoid2" parent="XROrigin3D/RightHandMesh" instance=ExtResource("3_oifi1")]
|
||||||
|
|
||||||
|
[node name="XRHandModifier3D" type="XRHandModifier3D" parent="XROrigin3D/RightHandMesh/RightHandHumanoid2/RightHandHumanoid/Skeleton3D" index="1"]
|
||||||
|
hand_tracker = &"/user/hand_tracker/right"
|
||||||
|
|
||||||
|
[editable path="XROrigin3D/LeftHandMesh/LeftHandHumanoid2"]
|
||||||
|
[editable path="XROrigin3D/RightHandMesh/RightHandHumanoid2"]
|
||||||
25
xr/openxr_hand_tracking_demo/objects/box.tscn
Normal file
25
xr/openxr_hand_tracking_demo/objects/box.tscn
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://cerkxyasq8t8b"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://pickup/pickup_able_body.gd" id="1_mxwa3"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b1waowk6l76ap" path="res://assets/images/pattern.png" id="1_t4uiq"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_jjy5v"]
|
||||||
|
margin = 0.001
|
||||||
|
size = Vector3(0.1, 0.1, 0.1)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ecfgs"]
|
||||||
|
albedo_texture = ExtResource("1_t4uiq")
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ajubj"]
|
||||||
|
material = SubResource("StandardMaterial3D_ecfgs")
|
||||||
|
size = Vector3(0.1, 0.1, 0.1)
|
||||||
|
|
||||||
|
[node name="Box" type="RigidBody3D"]
|
||||||
|
script = ExtResource("1_mxwa3")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("BoxShape3D_jjy5v")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
|
mesh = SubResource("BoxMesh_ajubj")
|
||||||
|
skeleton = NodePath("../CollisionShape3D")
|
||||||
65
xr/openxr_hand_tracking_demo/objects/table.tscn
Normal file
65
xr/openxr_hand_tracking_demo/objects/table.tscn
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
[gd_scene load_steps=8 format=3 uid="uid://hanl00aqvu7u"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b1waowk6l76ap" path="res://assets/images/pattern.png" id="1_h5hgt"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_vtble"]
|
||||||
|
size = Vector3(1, 0.1, 0.5)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_yh46n"]
|
||||||
|
albedo_color = Color(0.704983, 0.442908, 0.226976, 1)
|
||||||
|
albedo_texture = ExtResource("1_h5hgt")
|
||||||
|
uv1_scale = Vector3(3, 1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ud4mc"]
|
||||||
|
material = SubResource("StandardMaterial3D_yh46n")
|
||||||
|
size = Vector3(1, 0.1, 0.5)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_dgs2r"]
|
||||||
|
size = Vector3(0.1, 0.7, 0.1)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_gf8o1"]
|
||||||
|
albedo_color = Color(0.754123, 0.902538, 0.996894, 1)
|
||||||
|
albedo_texture = ExtResource("1_h5hgt")
|
||||||
|
uv1_scale = Vector3(1, 3, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_l0vgn"]
|
||||||
|
material = SubResource("StandardMaterial3D_gf8o1")
|
||||||
|
size = Vector3(0.1, 0.7, 0.1)
|
||||||
|
|
||||||
|
[node name="Table" type="StaticBody3D"]
|
||||||
|
|
||||||
|
[node name="TableSurfaceShape" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.75, 0)
|
||||||
|
shape = SubResource("BoxShape3D_vtble")
|
||||||
|
|
||||||
|
[node name="TableSurfaceMesh" type="MeshInstance3D" parent="TableSurfaceShape"]
|
||||||
|
mesh = SubResource("BoxMesh_ud4mc")
|
||||||
|
skeleton = NodePath("../..")
|
||||||
|
|
||||||
|
[node name="TableLegShape01" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.45, 0.35, -0.2)
|
||||||
|
shape = SubResource("BoxShape3D_dgs2r")
|
||||||
|
|
||||||
|
[node name="TableLegMesh" type="MeshInstance3D" parent="TableLegShape01"]
|
||||||
|
mesh = SubResource("BoxMesh_l0vgn")
|
||||||
|
|
||||||
|
[node name="TableLegShape02" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.45, 0.35, -0.2)
|
||||||
|
shape = SubResource("BoxShape3D_dgs2r")
|
||||||
|
|
||||||
|
[node name="TableLegMesh" type="MeshInstance3D" parent="TableLegShape02"]
|
||||||
|
mesh = SubResource("BoxMesh_l0vgn")
|
||||||
|
|
||||||
|
[node name="TableLegShape03" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.45, 0.35, 0.2)
|
||||||
|
shape = SubResource("BoxShape3D_dgs2r")
|
||||||
|
|
||||||
|
[node name="TableLegMesh" type="MeshInstance3D" parent="TableLegShape03"]
|
||||||
|
mesh = SubResource("BoxMesh_l0vgn")
|
||||||
|
|
||||||
|
[node name="TableLegShape04" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.45, 0.35, 0.2)
|
||||||
|
shape = SubResource("BoxShape3D_dgs2r")
|
||||||
|
|
||||||
|
[node name="TableLegMesh" type="MeshInstance3D" parent="TableLegShape04"]
|
||||||
|
mesh = SubResource("BoxMesh_l0vgn")
|
||||||
99
xr/openxr_hand_tracking_demo/openxr_action_map.tres
Normal file
99
xr/openxr_hand_tracking_demo/openxr_action_map.tres
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
[gd_resource type="OpenXRActionMap" load_steps=23 format=3 uid="uid://dydgx5ktpcmdl"]
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRAction" id="OpenXRAction_ywi2s"]
|
||||||
|
resource_name = "pose"
|
||||||
|
localized_name = "Pose"
|
||||||
|
action_type = 3
|
||||||
|
toplevel_paths = PackedStringArray("/user/hand/left", "/user/hand/right")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRAction" id="OpenXRAction_vayrd"]
|
||||||
|
resource_name = "haptic"
|
||||||
|
localized_name = "Haptic"
|
||||||
|
action_type = 4
|
||||||
|
toplevel_paths = PackedStringArray("/user/hand/left", "/user/hand/right")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRAction" id="OpenXRAction_h3dsb"]
|
||||||
|
resource_name = "pickup"
|
||||||
|
localized_name = "Pickup"
|
||||||
|
toplevel_paths = PackedStringArray("/user/hand/left", "/user/hand/right")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRActionSet" id="OpenXRActionSet_c2hwm"]
|
||||||
|
resource_name = "godot"
|
||||||
|
localized_name = "Godot action set"
|
||||||
|
actions = [SubResource("OpenXRAction_ywi2s"), SubResource("OpenXRAction_vayrd"), SubResource("OpenXRAction_h3dsb")]
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_r6sxc"]
|
||||||
|
action = SubResource("OpenXRAction_ywi2s")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/grip/pose", "/user/hand/right/input/grip/pose")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_j0h30"]
|
||||||
|
action = SubResource("OpenXRAction_vayrd")
|
||||||
|
paths = PackedStringArray("/user/hand/left/output/haptic", "/user/hand/right/output/haptic")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_govyu"]
|
||||||
|
action = SubResource("OpenXRAction_h3dsb")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/select/click", "/user/hand/right/input/select/click")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_643al"]
|
||||||
|
interaction_profile_path = "/interaction_profiles/khr/simple_controller"
|
||||||
|
bindings = [SubResource("OpenXRIPBinding_r6sxc"), SubResource("OpenXRIPBinding_j0h30"), SubResource("OpenXRIPBinding_govyu")]
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_fd646"]
|
||||||
|
action = SubResource("OpenXRAction_h3dsb")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/grasp_ext/value", "/user/hand/right/input/grasp_ext/value")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_wkfos"]
|
||||||
|
action = SubResource("OpenXRAction_ywi2s")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/grip/pose", "/user/hand/right/input/grip/pose")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_nhhi0"]
|
||||||
|
interaction_profile_path = "/interaction_profiles/ext/hand_interaction_ext"
|
||||||
|
bindings = [SubResource("OpenXRIPBinding_fd646"), SubResource("OpenXRIPBinding_wkfos")]
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_gv55f"]
|
||||||
|
action = SubResource("OpenXRAction_ywi2s")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/grip/pose", "/user/hand/right/input/grip/pose")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_mp0xr"]
|
||||||
|
action = SubResource("OpenXRAction_h3dsb")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/squeeze/value", "/user/hand/right/input/squeeze/value")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_86te5"]
|
||||||
|
action = SubResource("OpenXRAction_vayrd")
|
||||||
|
paths = PackedStringArray("/user/hand/left/output/haptic", "/user/hand/right/output/haptic")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_wrsh4"]
|
||||||
|
interaction_profile_path = "/interaction_profiles/oculus/touch_controller"
|
||||||
|
bindings = [SubResource("OpenXRIPBinding_gv55f"), SubResource("OpenXRIPBinding_mp0xr"), SubResource("OpenXRIPBinding_86te5")]
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_n476d"]
|
||||||
|
action = SubResource("OpenXRAction_ywi2s")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/grip/pose", "/user/hand/right/input/grip/pose")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_dh54r"]
|
||||||
|
action = SubResource("OpenXRAction_h3dsb")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/squeeze/value", "/user/hand/right/input/squeeze/value")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_tc2nk"]
|
||||||
|
action = SubResource("OpenXRAction_vayrd")
|
||||||
|
paths = PackedStringArray("/user/hand/left/output/haptic", "/user/hand/right/output/haptic")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_lah6t"]
|
||||||
|
interaction_profile_path = "/interaction_profiles/valve/index_controller"
|
||||||
|
bindings = [SubResource("OpenXRIPBinding_n476d"), SubResource("OpenXRIPBinding_dh54r"), SubResource("OpenXRIPBinding_tc2nk")]
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_vhdol"]
|
||||||
|
action = SubResource("OpenXRAction_ywi2s")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/grip/pose", "/user/hand/right/input/grip/pose")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_pwv0l"]
|
||||||
|
action = SubResource("OpenXRAction_h3dsb")
|
||||||
|
paths = PackedStringArray("/user/hand/left/input/squeeze/value", "/user/hand/right/input/squeeze/value")
|
||||||
|
|
||||||
|
[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_51rtw"]
|
||||||
|
interaction_profile_path = "/interaction_profiles/microsoft/hand_interaction"
|
||||||
|
bindings = [SubResource("OpenXRIPBinding_vhdol"), SubResource("OpenXRIPBinding_pwv0l")]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
action_sets = [SubResource("OpenXRActionSet_c2hwm")]
|
||||||
|
interaction_profiles = [SubResource("OpenXRInteractionProfile_643al"), SubResource("OpenXRInteractionProfile_nhhi0"), SubResource("OpenXRInteractionProfile_wrsh4"), SubResource("OpenXRInteractionProfile_lah6t"), SubResource("OpenXRInteractionProfile_51rtw")]
|
||||||
111
xr/openxr_hand_tracking_demo/pickup/pickup_able_body.gd
Normal file
111
xr/openxr_hand_tracking_demo/pickup/pickup_able_body.gd
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
extends RigidBody3D
|
||||||
|
class_name PickupAbleBody3D
|
||||||
|
|
||||||
|
|
||||||
|
var highlight_material : Material = preload("res://shaders/highlight_material.tres")
|
||||||
|
var picked_up_by : Area3D
|
||||||
|
var closest_areas : Array
|
||||||
|
|
||||||
|
var original_parent : Node3D
|
||||||
|
var tween : Tween
|
||||||
|
|
||||||
|
# Called when this object becomes the closest body in an area
|
||||||
|
func add_is_closest(area : Area3D) -> void:
|
||||||
|
if not closest_areas.has(area):
|
||||||
|
closest_areas.push_back(area)
|
||||||
|
|
||||||
|
_update_highlight()
|
||||||
|
|
||||||
|
|
||||||
|
# Called when this object becomes the closest body in an area
|
||||||
|
func remove_is_closest(area : Area3D) -> void:
|
||||||
|
if closest_areas.has(area):
|
||||||
|
closest_areas.erase(area)
|
||||||
|
|
||||||
|
_update_highlight()
|
||||||
|
|
||||||
|
|
||||||
|
# Returns whether we have been picked up.
|
||||||
|
func is_picked_up() -> bool:
|
||||||
|
# If we have a valid picked up by object,
|
||||||
|
# we've been picked up
|
||||||
|
if picked_up_by:
|
||||||
|
return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
# Pick this object up.
|
||||||
|
func pick_up(pick_up_by) -> void:
|
||||||
|
# Already picked up? Can't pick up twice.
|
||||||
|
if picked_up_by:
|
||||||
|
if picked_up_by == pick_up_by:
|
||||||
|
return
|
||||||
|
|
||||||
|
let_go()
|
||||||
|
|
||||||
|
# Remember some state we want to reapply on release.
|
||||||
|
original_parent = get_parent()
|
||||||
|
var current_transform = global_transform
|
||||||
|
|
||||||
|
# Remove us from our old parent.
|
||||||
|
original_parent.remove_child(self)
|
||||||
|
|
||||||
|
# Process our pickup.
|
||||||
|
picked_up_by = pick_up_by
|
||||||
|
picked_up_by.add_child(self)
|
||||||
|
global_transform = current_transform
|
||||||
|
freeze = true
|
||||||
|
|
||||||
|
# Kill any existing tween and create a new one.
|
||||||
|
if tween:
|
||||||
|
tween.kill()
|
||||||
|
tween = create_tween()
|
||||||
|
|
||||||
|
# Snap the object to this transform.
|
||||||
|
var snap_to : Transform3D
|
||||||
|
|
||||||
|
# Add code here to determine snap position and orientation.
|
||||||
|
|
||||||
|
# Now tween
|
||||||
|
tween.tween_property(self, "transform", snap_to, 0.1)
|
||||||
|
|
||||||
|
|
||||||
|
# Let this object go.
|
||||||
|
func let_go() -> void:
|
||||||
|
# Ignore if we haven't been picked up.
|
||||||
|
if not picked_up_by:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Cancel any ongoing tween
|
||||||
|
if tween:
|
||||||
|
tween.kill()
|
||||||
|
tween = null
|
||||||
|
|
||||||
|
# Remember our current transform.
|
||||||
|
var current_transform = global_transform
|
||||||
|
|
||||||
|
# Remove us from what picked us up.
|
||||||
|
picked_up_by.remove_child(self)
|
||||||
|
picked_up_by = null
|
||||||
|
|
||||||
|
# Reset some state.
|
||||||
|
original_parent.add_child(self)
|
||||||
|
global_transform = current_transform
|
||||||
|
freeze = false
|
||||||
|
|
||||||
|
|
||||||
|
# Update our highlight to show that we can be picked up
|
||||||
|
func _update_highlight() -> void:
|
||||||
|
if not picked_up_by and not closest_areas.is_empty():
|
||||||
|
# add highlight
|
||||||
|
for child in get_children():
|
||||||
|
if child is MeshInstance3D:
|
||||||
|
var mesh_instance : MeshInstance3D = child
|
||||||
|
mesh_instance.material_overlay = highlight_material
|
||||||
|
else:
|
||||||
|
# remove highlight
|
||||||
|
for child in get_children():
|
||||||
|
if child is MeshInstance3D:
|
||||||
|
var mesh_instance : MeshInstance3D = child
|
||||||
|
mesh_instance.material_overlay = null
|
||||||
118
xr/openxr_hand_tracking_demo/pickup/pickup_handler.gd
Normal file
118
xr/openxr_hand_tracking_demo/pickup/pickup_handler.gd
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
@tool
|
||||||
|
extends Area3D
|
||||||
|
class_name PickupHandler3D
|
||||||
|
|
||||||
|
# This area3D class detects all physics bodys based on
|
||||||
|
# PickupAbleBody3D within range and handles the logic
|
||||||
|
# for selecting the closest one and allowing pickup
|
||||||
|
# of that object.
|
||||||
|
|
||||||
|
# Detect range specifies within what radius we detect
|
||||||
|
# objects we can pick up.
|
||||||
|
@export var detect_range : float = 0.3:
|
||||||
|
set(value):
|
||||||
|
detect_range = value
|
||||||
|
if is_inside_tree():
|
||||||
|
_update_detect_range()
|
||||||
|
_update_closest_body()
|
||||||
|
|
||||||
|
# Pickup Action specifies the action in the OpenXR
|
||||||
|
# action map that triggers our pickup function.
|
||||||
|
@export var pickup_action : String = "pickup"
|
||||||
|
|
||||||
|
var closest_body : PickupAbleBody3D
|
||||||
|
var picked_up_body: PickupAbleBody3D
|
||||||
|
var was_pickup_pressed : bool = false
|
||||||
|
|
||||||
|
# Update our detection range.
|
||||||
|
func _update_detect_range() -> void:
|
||||||
|
var shape : SphereShape3D = $CollisionShape3D.shape
|
||||||
|
if shape:
|
||||||
|
shape.radius = detect_range
|
||||||
|
|
||||||
|
|
||||||
|
# Update our closest body.
|
||||||
|
func _update_closest_body() -> void:
|
||||||
|
# Do not do this when we're in the editor.
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Do not check this if we've picked something up.
|
||||||
|
if picked_up_body:
|
||||||
|
if closest_body:
|
||||||
|
closest_body.remove_is_closest(self)
|
||||||
|
closest_body = null
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# Find the body that is currently the closest.
|
||||||
|
var new_closest_body : PickupAbleBody3D
|
||||||
|
var closest_distance : float = 1000000.0
|
||||||
|
|
||||||
|
for body in get_overlapping_bodies():
|
||||||
|
if body is PickupAbleBody3D and not body.is_picked_up():
|
||||||
|
var distance_squared = (body.global_position - global_position).length_squared()
|
||||||
|
if distance_squared < closest_distance:
|
||||||
|
new_closest_body = body
|
||||||
|
closest_distance = distance_squared
|
||||||
|
|
||||||
|
# Unchanged? Just exit
|
||||||
|
if closest_body == new_closest_body:
|
||||||
|
return
|
||||||
|
|
||||||
|
# We had a closest body
|
||||||
|
if closest_body:
|
||||||
|
closest_body.remove_is_closest(self)
|
||||||
|
|
||||||
|
closest_body = new_closest_body
|
||||||
|
if closest_body:
|
||||||
|
closest_body.add_is_closest(self)
|
||||||
|
|
||||||
|
|
||||||
|
# Get our controller that we are a child of
|
||||||
|
func _get_parent_controller() -> XRController3D:
|
||||||
|
var parent : Node = get_parent()
|
||||||
|
while parent:
|
||||||
|
if parent is XRController3D:
|
||||||
|
return parent
|
||||||
|
|
||||||
|
parent = parent.get_parent()
|
||||||
|
|
||||||
|
return null
|
||||||
|
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
_update_detect_range()
|
||||||
|
_update_closest_body()
|
||||||
|
|
||||||
|
|
||||||
|
# Called every physics frame
|
||||||
|
func _physics_process(delta) -> void:
|
||||||
|
# As we move our hands we need to check if the closest body
|
||||||
|
# has changed.
|
||||||
|
_update_closest_body()
|
||||||
|
|
||||||
|
# Check if our pickup action is true
|
||||||
|
var pickup_pressed = false
|
||||||
|
var controller : XRController3D = _get_parent_controller()
|
||||||
|
if controller:
|
||||||
|
# While OpenXR can return this as a boolean, there is a lot of
|
||||||
|
# difference in handling thresholds between platforms.
|
||||||
|
# So we implement our own logic here.
|
||||||
|
var pickup_value : float = controller.get_float(pickup_action)
|
||||||
|
var threshold : float = 0.4 if was_pickup_pressed else 0.6
|
||||||
|
pickup_pressed = pickup_value > threshold
|
||||||
|
|
||||||
|
# Do we need to let go?
|
||||||
|
if picked_up_body and not pickup_pressed:
|
||||||
|
picked_up_body.let_go()
|
||||||
|
picked_up_body = null
|
||||||
|
|
||||||
|
# Do we need to pick something up
|
||||||
|
if not picked_up_body and not was_pickup_pressed and pickup_pressed and closest_body:
|
||||||
|
picked_up_body = closest_body
|
||||||
|
picked_up_body.pick_up(self)
|
||||||
|
|
||||||
|
# Remember our state for the next frame
|
||||||
|
was_pickup_pressed = pickup_pressed
|
||||||
18
xr/openxr_hand_tracking_demo/pickup/pickup_handler.tscn
Normal file
18
xr/openxr_hand_tracking_demo/pickup/pickup_handler.tscn
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://byif52d1xkl3u"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://pickup/pickup_handler.gd" id="1_5qec3"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_i5on0"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
margin = 0.001
|
||||||
|
radius = 0.3
|
||||||
|
|
||||||
|
[node name="PickupHandler" type="Area3D"]
|
||||||
|
script = ExtResource("1_5qec3")
|
||||||
|
pickup_action = null
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("SphereShape3D_i5on0")
|
||||||
|
|
||||||
|
[connection signal="body_entered" from="." to="." method="_on_body_entered"]
|
||||||
|
[connection signal="body_exited" from="." to="." method="_on_body_exited"]
|
||||||
39
xr/openxr_hand_tracking_demo/project.godot
Normal file
39
xr/openxr_hand_tracking_demo/project.godot
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=5
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="openxr_hand_tracking_demo"
|
||||||
|
run/main_scene="res://main.tscn"
|
||||||
|
config/features=PackedStringArray("4.3", "GL Compatibility")
|
||||||
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[debug]
|
||||||
|
|
||||||
|
settings/stdout/verbose_stdout=true
|
||||||
|
|
||||||
|
[editor_plugins]
|
||||||
|
|
||||||
|
enabled=PackedStringArray()
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
renderer/rendering_method="gl_compatibility"
|
||||||
|
renderer/rendering_method.mobile="gl_compatibility"
|
||||||
|
textures/vram_compression/import_etc2_astc=true
|
||||||
|
|
||||||
|
[xr]
|
||||||
|
|
||||||
|
openxr/enabled=true
|
||||||
|
openxr/reference_space=2
|
||||||
|
openxr/foveation_level=2
|
||||||
|
openxr/foveation_dynamic=true
|
||||||
|
openxr/extensions/hand_interaction_profile=true
|
||||||
|
shaders/enabled=true
|
||||||
BIN
xr/openxr_hand_tracking_demo/screenshots/hand_tracking_demo.png
Normal file
BIN
xr/openxr_hand_tracking_demo/screenshots/hand_tracking_demo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 717 KiB |
@@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dvj2ofetki3oi"
|
||||||
|
path="res://.godot/imported/hand_tracking_demo.png-7ba3fe63e5b4cae9d220943b88a7ab14.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://screenshots/hand_tracking_demo.png"
|
||||||
|
dest_files=["res://.godot/imported/hand_tracking_demo.png-7ba3fe63e5b4cae9d220943b88a7ab14.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
12
xr/openxr_hand_tracking_demo/shaders/highlight_material.tres
Normal file
12
xr/openxr_hand_tracking_demo/shaders/highlight_material.tres
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://bys74qhnreu01"]
|
||||||
|
|
||||||
|
[ext_resource type="Shader" uid="uid://cs1jlvgrhd4ac" path="res://shaders/highlight_shader.tres" id="1_gvs70"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
render_priority = 0
|
||||||
|
shader = ExtResource("1_gvs70")
|
||||||
|
shader_parameter/albedo = Color(0.727706, 0.726254, 0, 1)
|
||||||
|
shader_parameter/grow = 0.002
|
||||||
|
shader_parameter/specular = 0.5
|
||||||
|
shader_parameter/metallic = 0.0
|
||||||
|
shader_parameter/roughness = 1.0
|
||||||
28
xr/openxr_hand_tracking_demo/shaders/highlight_shader.tres
Normal file
28
xr/openxr_hand_tracking_demo/shaders/highlight_shader.tres
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
[gd_resource type="Shader" format=3 uid="uid://cs1jlvgrhd4ac"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
code = "// NOTE: Shader automatically converted from Godot Engine 4.3.beta1's StandardMaterial3D.
|
||||||
|
|
||||||
|
shader_type spatial;
|
||||||
|
render_mode blend_mix, depth_draw_opaque, cull_front, diffuse_burley, specular_schlick_ggx, unshaded;
|
||||||
|
|
||||||
|
uniform vec4 albedo : source_color;
|
||||||
|
uniform float grow : hint_range(-16.0, 16.0, 0.001);
|
||||||
|
|
||||||
|
uniform float specular : hint_range(0.0, 1.0, 0.01);
|
||||||
|
uniform float metallic : hint_range(0.0, 1.0, 0.01);
|
||||||
|
uniform float roughness : hint_range(0.0, 1.0);
|
||||||
|
|
||||||
|
void vertex() {
|
||||||
|
// Standard grow along the normal will create seams
|
||||||
|
VERTEX += normalize(VERTEX) * grow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
ALBEDO = albedo.rgb;
|
||||||
|
|
||||||
|
METALLIC = metallic;
|
||||||
|
SPECULAR = specular;
|
||||||
|
ROUGHNESS = roughness;
|
||||||
|
}
|
||||||
|
"
|
||||||
112
xr/openxr_hand_tracking_demo/start_vr.gd
Normal file
112
xr/openxr_hand_tracking_demo/start_vr.gd
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
signal focus_lost
|
||||||
|
signal focus_gained
|
||||||
|
signal pose_recentered
|
||||||
|
|
||||||
|
@export var maximum_refresh_rate : int = 90
|
||||||
|
|
||||||
|
var xr_interface : OpenXRInterface
|
||||||
|
var xr_is_focused := false
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
xr_interface = XRServer.find_interface("OpenXR")
|
||||||
|
if xr_interface and xr_interface.is_initialized():
|
||||||
|
print("OpenXR instantiated successfully.")
|
||||||
|
var vp : Viewport = get_viewport()
|
||||||
|
|
||||||
|
# Enable XR on our viewport.
|
||||||
|
vp.use_xr = true
|
||||||
|
|
||||||
|
# Make sure V-Sync is off, as V-Sync is handled by OpenXR.
|
||||||
|
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
|
||||||
|
|
||||||
|
# Enable variable rate shading.
|
||||||
|
if RenderingServer.get_rendering_device():
|
||||||
|
vp.vrs_mode = Viewport.VRS_XR
|
||||||
|
elif int(ProjectSettings.get_setting("xr/openxr/foveation_level")) == 0:
|
||||||
|
push_warning("OpenXR: Recommend setting Foveation level to High in Project Settings")
|
||||||
|
|
||||||
|
# Connect the OpenXR events.
|
||||||
|
xr_interface.session_begun.connect(_on_openxr_session_begun)
|
||||||
|
xr_interface.session_visible.connect(_on_openxr_visible_state)
|
||||||
|
xr_interface.session_focussed.connect(_on_openxr_focused_state)
|
||||||
|
xr_interface.session_stopping.connect(_on_openxr_stopping)
|
||||||
|
xr_interface.pose_recentered.connect(_on_openxr_pose_recentered)
|
||||||
|
else:
|
||||||
|
# We couldn't start OpenXR.
|
||||||
|
print("OpenXR not instantiated!")
|
||||||
|
get_tree().quit()
|
||||||
|
|
||||||
|
|
||||||
|
# Handle OpenXR session ready.
|
||||||
|
func _on_openxr_session_begun() -> void:
|
||||||
|
# Get the reported refresh rate.
|
||||||
|
var current_refresh_rate := xr_interface.get_display_refresh_rate()
|
||||||
|
if current_refresh_rate > 0:
|
||||||
|
print("OpenXR: Refresh rate reported as ", str(current_refresh_rate))
|
||||||
|
else:
|
||||||
|
print("OpenXR: No refresh rate given by XR runtime")
|
||||||
|
|
||||||
|
# See if we have a better refresh rate available.
|
||||||
|
var new_rate := current_refresh_rate
|
||||||
|
var available_rates: Array = xr_interface.get_available_display_refresh_rates()
|
||||||
|
if available_rates.is_empty():
|
||||||
|
print("OpenXR: Target does not support refresh rate extension")
|
||||||
|
elif available_rates.size() == 1:
|
||||||
|
# Only one available, so use it.
|
||||||
|
new_rate = available_rates[0]
|
||||||
|
else:
|
||||||
|
for rate in available_rates:
|
||||||
|
if rate > new_rate and rate <= maximum_refresh_rate:
|
||||||
|
new_rate = rate
|
||||||
|
|
||||||
|
# Did we find a better rate?
|
||||||
|
if current_refresh_rate != new_rate:
|
||||||
|
print("OpenXR: Setting refresh rate to ", str(new_rate))
|
||||||
|
xr_interface.set_display_refresh_rate(new_rate)
|
||||||
|
current_refresh_rate = new_rate
|
||||||
|
|
||||||
|
# Now match our physics rate. This is currently needed to avoid jittering,
|
||||||
|
# due to physics interpolation not being used.
|
||||||
|
Engine.physics_ticks_per_second = roundi(current_refresh_rate)
|
||||||
|
|
||||||
|
|
||||||
|
# Handle OpenXR visible state.
|
||||||
|
func _on_openxr_visible_state() -> void:
|
||||||
|
# We always pass this state at startup,
|
||||||
|
# but the second time we get this, it means our player took off their headset.
|
||||||
|
if xr_is_focused:
|
||||||
|
print("OpenXR lost focus")
|
||||||
|
|
||||||
|
xr_is_focused = false
|
||||||
|
|
||||||
|
# Pause our game.
|
||||||
|
process_mode = Node.PROCESS_MODE_DISABLED
|
||||||
|
|
||||||
|
focus_lost.emit()
|
||||||
|
|
||||||
|
|
||||||
|
# Handle OpenXR focused state
|
||||||
|
func _on_openxr_focused_state() -> void:
|
||||||
|
print("OpenXR gained focus")
|
||||||
|
xr_is_focused = true
|
||||||
|
|
||||||
|
# Unpause our game.
|
||||||
|
process_mode = Node.PROCESS_MODE_INHERIT
|
||||||
|
|
||||||
|
focus_gained.emit()
|
||||||
|
|
||||||
|
|
||||||
|
# Handle OpenXR stopping state.
|
||||||
|
func _on_openxr_stopping() -> void:
|
||||||
|
# Our session is being stopped.
|
||||||
|
print("OpenXR is stopping")
|
||||||
|
|
||||||
|
|
||||||
|
# Handle OpenXR pose recentered signal.
|
||||||
|
func _on_openxr_pose_recentered() -> void:
|
||||||
|
# User recentered view, we have to react to this by recentering the view.
|
||||||
|
# This is game implementation dependent.
|
||||||
|
pose_recentered.emit()
|
||||||
Reference in New Issue
Block a user