Merge pull request #1218 from BastiaanOlij/openxr_render_models_demo

Added an OpenXR render models demo
This commit is contained in:
Matthew
2025-07-14 15:59:26 -04:00
committed by GitHub
18 changed files with 656 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

4
xr/openxr_render_models/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Godot 4+ specific ignores
.godot/
.editorconfig
/android/

View File

@@ -0,0 +1,50 @@
# OpenXR Render models demo
This is a demo showing OpenXR's render models implementation.
Language: GDScript
Renderer: Compatibility
> [!NOTE]
>
> This demo requires Godot 4.5 or later
## Screenshots
![Screenshot](screenshots/render_model_demo.png)
## How does it work?
OpenXR allows us to run our application without having knowledge of the hardware being used,
or that we as developers have access too at the time of developing our application.
As a result we don't have direct information telling us what hardware is being used,
however there are situations where we want to visually show this hardware.
This specifically applies to the controllers used by the user, as showing the correct hardware
improves the user's sense of immersion.
The render model API allows us to enumerate the devices currently in use and then query
information such as its 3D asset, its position and orientation in space, and the position
and orientation of individual components of the asset.
Godot's implementation hides most of the complexity of this through the OpenXRRenderModelManager
node as a child of the XROrigin3D node. You can add just this node by itself and let it show
all render models that are currently active, or like we do in this demo, you can add nodes
in the tree of each controller to show render models related to that controller.
## Action map
This demo project has a barebones action map as we're only dealing with positioning.
## Running on PCVR
This project can be run as normal for PCVR. Ensure that an OpenXR runtime has been installed.
## 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).

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,41 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://btobyv4xjhltq"
path.s3tc="res://.godot/imported/pattern.png-cf6f03dfd1cdd4bc35da3414e912103d.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://assets/pattern.png"
dest_files=["res://.godot/imported/pattern.png-cf6f03dfd1cdd4bc35da3414e912103d.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
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/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
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

View File

@@ -0,0 +1,21 @@
[gd_scene load_steps=5 format=3 uid="uid://cfgfwisj8m2mg"]
[ext_resource type="Texture2D" uid="uid://btobyv4xjhltq" path="res://assets/pattern.png" id="1_g2tbl"]
[sub_resource type="BoxShape3D" id="BoxShape3D_oq5cr"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_bqn3j"]
albedo_color = Color(0.16217351, 0.546357, 0.5366536, 1)
albedo_texture = ExtResource("1_g2tbl")
uv1_scale = Vector3(3, 3, 3)
[sub_resource type="BoxMesh" id="BoxMesh_3n43a"]
material = SubResource("StandardMaterial3D_bqn3j")
[node name="Box" type="RigidBody3D"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("BoxShape3D_oq5cr")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("BoxMesh_3n43a")

View File

@@ -0,0 +1,19 @@
class_name CollisionHands3D
extends AnimatableBody3D
func _ready():
# Make sure these are set correctly.
top_level = true
sync_to_physics = false
process_physics_priority = -90
func _physics_process(_delta):
# Follow our parent node around.
var dest_transform = get_parent().global_transform
# We just apply rotation for this example.
global_basis = dest_transform.basis
# Attempt to move to where our tracked hand is.
move_and_collide(dest_transform.origin - global_position)

View File

@@ -0,0 +1 @@
uid://c5bnmb8grcumh

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><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 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>

After

Width:  |  Height:  |  Size: 995 B

View File

@@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bi6bu4ng584fq"
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/uastc_level=0
compress/rdo_quality_loss=0.0
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/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
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

View File

@@ -0,0 +1,122 @@
[gd_scene load_steps=13 format=3 uid="uid://btli1dajen53o"]
[ext_resource type="Script" uid="uid://bqa4r4n7b6d7s" path="res://start_vr.gd" id="1_1bvp3"]
[ext_resource type="Script" uid="uid://c5bnmb8grcumh" path="res://collision_hands.gd" id="1_ig7tw"]
[ext_resource type="Texture2D" uid="uid://btobyv4xjhltq" path="res://assets/pattern.png" id="2_h2yge"]
[ext_resource type="PackedScene" uid="uid://cfgfwisj8m2mg" path="res://box.tscn" id="3_1bvp3"]
[ext_resource type="PackedScene" uid="uid://c7ohc2o1shtu7" path="res://wall.tscn" id="5_lquwl"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_7dm0k"]
sky_horizon_color = Color(0.662243, 0.671743, 0.686743, 1)
ground_horizon_color = Color(0.662243, 0.671743, 0.686743, 1)
[sub_resource type="Sky" id="Sky_ig7tw"]
sky_material = SubResource("ProceduralSkyMaterial_7dm0k")
[sub_resource type="Environment" id="Environment_0xm2m"]
background_mode = 2
sky = SubResource("Sky_ig7tw")
tonemap_mode = 2
[sub_resource type="SphereShape3D" id="SphereShape3D_0xm2m"]
radius = 0.02
[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_lquwl"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_7mycd"]
albedo_color = Color(0.3241276, 0.50004333, 0.2159737, 1)
albedo_texture = ExtResource("2_h2yge")
uv1_scale = Vector3(100, 100, 100)
[sub_resource type="PlaneMesh" id="PlaneMesh_272bh"]
material = SubResource("StandardMaterial3D_7mycd")
size = Vector2(1000, 1000)
[node name="Main" type="Node3D"]
[node name="StartVR" type="Node3D" parent="."]
script = ExtResource("1_1bvp3")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(-0.866025, -0.433013, 0.25, 0, 0.5, 0.866025, -0.5, 0.75, -0.433013, 0, 0, 0)
shadow_enabled = true
shadow_bias = 0.01
directional_shadow_max_distance = 50.0
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_0xm2m")
[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="OpenXRRenderManager" type="OpenXRRenderModelManager" parent="XROrigin3D"]
tracker = 1
[node name="LeftHand" type="XRController3D" parent="XROrigin3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 1, -0.5)
tracker = &"left_hand"
pose = &"grip"
[node name="CollisionHands3D" type="AnimatableBody3D" parent="XROrigin3D/LeftHand"]
script = ExtResource("1_ig7tw")
metadata/_custom_type_script = "uid://c5bnmb8grcumh"
[node name="OpenXRRenderManager" type="OpenXRRenderModelManager" parent="XROrigin3D/LeftHand/CollisionHands3D"]
tracker = 2
make_local_to_pose = "grip"
[node name="CollisionShape3D" type="CollisionShape3D" parent="XROrigin3D/LeftHand/CollisionHands3D"]
shape = SubResource("SphereShape3D_0xm2m")
[node name="RightHand" type="XRController3D" parent="XROrigin3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.5, 1, -0.5)
tracker = &"right_hand"
pose = &"grip"
[node name="CollisionHands3D" type="AnimatableBody3D" parent="XROrigin3D/RightHand"]
script = ExtResource("1_ig7tw")
metadata/_custom_type_script = "uid://c5bnmb8grcumh"
[node name="OpenXRRenderManager" type="OpenXRRenderModelManager" parent="XROrigin3D/RightHand/CollisionHands3D"]
tracker = 3
make_local_to_pose = "grip"
[node name="CollisionShape3D" type="CollisionShape3D" parent="XROrigin3D/RightHand/CollisionHands3D"]
shape = SubResource("SphereShape3D_0xm2m")
[node name="Floor" type="StaticBody3D" parent="."]
[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor"]
shape = SubResource("WorldBoundaryShape3D_lquwl")
[node name="MeshInstance3D" type="MeshInstance3D" parent="Floor"]
mesh = SubResource("PlaneMesh_272bh")
[node name="Box" parent="." instance=ExtResource("3_1bvp3")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.75, 0.5, -0.75)
[node name="Wall01" parent="." instance=ExtResource("5_lquwl")]
transform = Transform3D(0.5077975, 0.073525466, 0.8583331, -0.14741239, 0.989072, 0.0024858303, -0.8487705, -0.12779121, 0.5130869, -1.3576927, -0.4236443, 0)
[node name="Wall02" parent="." instance=ExtResource("5_lquwl")]
transform = Transform3D(-0.4400646, -0.09660582, 0.89275444, 0, 0.9941961, 0.10758293, -0.89796615, 0.047343437, -0.43751052, 2.5047212, -0.106753826, 0.0325222)
[node name="Wall03" parent="." instance=ExtResource("5_lquwl")]
transform = Transform3D(0.584169, -0.048437964, 0.8101854, -0.1719119, 0.9681845, 0.181838, -0.7932168, -0.24550463, 0.5572562, 2.4887834, -0.7894809, 2.6100364)
[node name="Wall04" parent="." instance=ExtResource("5_lquwl")]
transform = Transform3D(-0.63450754, -0.2243154, 0.7396504, -0.12261418, 0.9740546, 0.19021934, -0.763129, 0.030003972, -0.64554924, -1.2827711, -0.22003722, 2.6100364)
[node name="Wall05" parent="." instance=ExtResource("5_lquwl")]
transform = Transform3D(-0.9373456, 0.2908417, 0.1918185, 0.3214552, 0.93427694, 0.1542501, -0.13434927, 0.20624672, -0.9692331, 0.36298275, -0.48010635, -3.1081657)
[node name="Wall06" parent="." instance=ExtResource("5_lquwl")]
transform = Transform3D(-0.990934, 0, 0.13434926, 0, 1, 0, -0.13434926, 0, -0.990934, 0.75976896, -0.70440745, 4.5405197)
[node name="Wall07" parent="." instance=ExtResource("5_lquwl")]
transform = Transform3D(0.02368374, 0.13314083, -0.99081427, -0.16938388, 0.97729725, 0.12727568, 0.9852657, 0.16481358, 0.045697965, 3.8073082, -0.5026467, 0.84226894)
[node name="Wall08" parent="." instance=ExtResource("5_lquwl")]
transform = Transform3D(0.023540916, 0.2297096, -0.9729746, -0.2009241, 0.95447266, 0.22048022, 0.97932404, 0.19030367, 0.06862336, -3.4319887, -0.45930338, 0.84226894)

View File

@@ -0,0 +1,140 @@
[gd_resource type="OpenXRActionMap" load_steps=33 format=3 uid="uid://cqrfv76xcmkca"]
[sub_resource type="OpenXRAction" id="OpenXRAction_m08eo"]
resource_name = "aim_pose"
localized_name = "Aim pose"
action_type = 3
toplevel_paths = PackedStringArray("/user/hand/left", "/user/hand/right")
[sub_resource type="OpenXRAction" id="OpenXRAction_c4j1d"]
resource_name = "grip_pose"
localized_name = "Grip pose"
action_type = 3
toplevel_paths = PackedStringArray("/user/hand/left", "/user/hand/right")
[sub_resource type="OpenXRAction" id="OpenXRAction_sow2k"]
resource_name = "haptic"
localized_name = "Haptic"
action_type = 4
toplevel_paths = PackedStringArray("/user/hand/left", "/user/hand/right", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/keyboard")
[sub_resource type="OpenXRActionSet" id="OpenXRActionSet_ngwcy"]
resource_name = "godot"
localized_name = "Godot action set"
actions = [SubResource("OpenXRAction_m08eo"), SubResource("OpenXRAction_c4j1d"), SubResource("OpenXRAction_sow2k")]
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_pjtev"]
action = SubResource("OpenXRAction_m08eo")
binding_path = "/user/hand/left/input/aim/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_nqyri"]
action = SubResource("OpenXRAction_m08eo")
binding_path = "/user/hand/right/input/aim/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_86uui"]
action = SubResource("OpenXRAction_c4j1d")
binding_path = "/user/hand/left/input/grip/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_nrtxc"]
action = SubResource("OpenXRAction_c4j1d")
binding_path = "/user/hand/right/input/grip/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_rjtq8"]
action = SubResource("OpenXRAction_sow2k")
binding_path = "/user/hand/left/output/haptic"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_lce2q"]
action = SubResource("OpenXRAction_sow2k")
binding_path = "/user/hand/right/output/haptic"
[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_ckeh6"]
interaction_profile_path = "/interaction_profiles/khr/simple_controller"
bindings = [SubResource("OpenXRIPBinding_pjtev"), SubResource("OpenXRIPBinding_nqyri"), SubResource("OpenXRIPBinding_86uui"), SubResource("OpenXRIPBinding_nrtxc"), SubResource("OpenXRIPBinding_rjtq8"), SubResource("OpenXRIPBinding_lce2q")]
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_chplt"]
action = SubResource("OpenXRAction_m08eo")
binding_path = "/user/hand/left/input/aim/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_obxrh"]
action = SubResource("OpenXRAction_m08eo")
binding_path = "/user/hand/right/input/aim/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_on7oi"]
action = SubResource("OpenXRAction_c4j1d")
binding_path = "/user/hand/left/input/grip/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_ege4h"]
action = SubResource("OpenXRAction_c4j1d")
binding_path = "/user/hand/right/input/grip/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_me87v"]
action = SubResource("OpenXRAction_sow2k")
binding_path = "/user/hand/left/output/haptic"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_d8myu"]
action = SubResource("OpenXRAction_sow2k")
binding_path = "/user/hand/right/output/haptic"
[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_hsh5n"]
interaction_profile_path = "/interaction_profiles/oculus/touch_controller"
bindings = [SubResource("OpenXRIPBinding_chplt"), SubResource("OpenXRIPBinding_obxrh"), SubResource("OpenXRIPBinding_on7oi"), SubResource("OpenXRIPBinding_ege4h"), SubResource("OpenXRIPBinding_me87v"), SubResource("OpenXRIPBinding_d8myu")]
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_gosqu"]
action = SubResource("OpenXRAction_m08eo")
binding_path = "/user/hand/left/input/aim/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_n52fm"]
action = SubResource("OpenXRAction_m08eo")
binding_path = "/user/hand/right/input/aim/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_vushy"]
action = SubResource("OpenXRAction_c4j1d")
binding_path = "/user/hand/left/input/grip/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_lbhgg"]
action = SubResource("OpenXRAction_c4j1d")
binding_path = "/user/hand/right/input/grip/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_8xxre"]
action = SubResource("OpenXRAction_sow2k")
binding_path = "/user/hand/left/output/haptic"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_jceb4"]
action = SubResource("OpenXRAction_sow2k")
binding_path = "/user/hand/right/output/haptic"
[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_lvl5r"]
interaction_profile_path = "/interaction_profiles/bytedance/pico4_controller"
bindings = [SubResource("OpenXRIPBinding_gosqu"), SubResource("OpenXRIPBinding_n52fm"), SubResource("OpenXRIPBinding_vushy"), SubResource("OpenXRIPBinding_lbhgg"), SubResource("OpenXRIPBinding_8xxre"), SubResource("OpenXRIPBinding_jceb4")]
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_34k6i"]
action = SubResource("OpenXRAction_m08eo")
binding_path = "/user/hand/left/input/aim/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_biq8g"]
action = SubResource("OpenXRAction_m08eo")
binding_path = "/user/hand/right/input/aim/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_7rnxc"]
action = SubResource("OpenXRAction_c4j1d")
binding_path = "/user/hand/left/input/grip/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_go0kb"]
action = SubResource("OpenXRAction_c4j1d")
binding_path = "/user/hand/right/input/grip/pose"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_nudtj"]
action = SubResource("OpenXRAction_sow2k")
binding_path = "/user/hand/left/output/haptic"
[sub_resource type="OpenXRIPBinding" id="OpenXRIPBinding_2a6v2"]
action = SubResource("OpenXRAction_sow2k")
binding_path = "/user/hand/right/output/haptic"
[sub_resource type="OpenXRInteractionProfile" id="OpenXRInteractionProfile_jhul1"]
interaction_profile_path = "/interaction_profiles/valve/index_controller"
bindings = [SubResource("OpenXRIPBinding_34k6i"), SubResource("OpenXRIPBinding_biq8g"), SubResource("OpenXRIPBinding_7rnxc"), SubResource("OpenXRIPBinding_go0kb"), SubResource("OpenXRIPBinding_nudtj"), SubResource("OpenXRIPBinding_2a6v2")]
[resource]
action_sets = [SubResource("OpenXRActionSet_ngwcy")]
interaction_profiles = [SubResource("OpenXRInteractionProfile_ckeh6"), SubResource("OpenXRInteractionProfile_hsh5n"), SubResource("OpenXRInteractionProfile_lvl5r"), SubResource("OpenXRInteractionProfile_jhul1")]

View File

@@ -0,0 +1,34 @@
; 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 render models"
run/main_scene="uid://btli1dajen53o"
config/features=PackedStringArray("4.5", "GL Compatibility")
config/icon="res://icon.svg"
[physics]
3d/physics_engine="Jolt Physics"
[rendering]
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"
[xr]
openxr/enabled=true
openxr/reference_space=2
openxr/foveation_level=3
openxr/foveation_dynamic=true
shaders/enabled=true
openxr/extensions/render_model=true

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://4eulsha6ncfa"
path="res://.godot/imported/render_model_demo.png-3043378ddd018812c86616f385e65c99.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://screenshots/render_model_demo.png"
dest_files=["res://.godot/imported/render_model_demo.png-3043378ddd018812c86616f385e65c99.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
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/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
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

View 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()

View File

@@ -0,0 +1 @@
uid://bqa4r4n7b6d7s

View File

@@ -0,0 +1,25 @@
[gd_scene load_steps=5 format=3 uid="uid://c7ohc2o1shtu7"]
[ext_resource type="Texture2D" uid="uid://btobyv4xjhltq" path="res://assets/pattern.png" id="1_xxgf6"]
[sub_resource type="BoxShape3D" id="BoxShape3D_oh6kn"]
size = Vector3(2, 2, 0.2)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_y4f30"]
albedo_color = Color(0.76257527, 0.49292004, 0.17555861, 1)
albedo_texture = ExtResource("1_xxgf6")
uv1_scale = Vector3(2, 2, 2)
[sub_resource type="BoxMesh" id="BoxMesh_xxgf6"]
material = SubResource("StandardMaterial3D_y4f30")
size = Vector3(2, 2, 0.2)
[node name="Wall" type="StaticBody3D"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
shape = SubResource("BoxShape3D_oh6kn")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
mesh = SubResource("BoxMesh_xxgf6")