summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/audio_listener_3d.h3
-rw-r--r--scene/3d/audio_stream_player_3d.cpp4
-rw-r--r--scene/3d/collision_object_3d.cpp4
-rw-r--r--scene/3d/cpu_particles_3d.h7
-rw-r--r--scene/3d/gpu_particles_3d.cpp1
-rw-r--r--scene/3d/navigation_agent_3d.cpp4
-rw-r--r--scene/3d/navigation_region_3d.cpp2
-rw-r--r--scene/3d/node_3d.cpp4
-rw-r--r--scene/3d/soft_dynamic_body_3d.cpp88
-rw-r--r--scene/3d/soft_dynamic_body_3d.h15
-rw-r--r--scene/3d/sprite_3d.h6
-rw-r--r--scene/3d/xr_nodes.cpp627
-rw-r--r--scene/3d/xr_nodes.h110
13 files changed, 490 insertions, 385 deletions
diff --git a/scene/3d/audio_listener_3d.h b/scene/3d/audio_listener_3d.h
index 492cacb0e9..31de3b4fb1 100644
--- a/scene/3d/audio_listener_3d.h
+++ b/scene/3d/audio_listener_3d.h
@@ -63,9 +63,6 @@ public:
virtual Transform3D get_listener_transform() const;
- void set_visible_layers(uint32_t p_layers);
- uint32_t get_visible_layers() const;
-
AudioListener3D();
~AudioListener3D();
};
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index c422070480..44a685f506 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -835,7 +835,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,Inverse Square,Log,Disabled"), "set_attenuation_model", "get_attenuation_model");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,Inverse Square,Logarithmic,Disabled"), "set_attenuation_model", "get_attenuation_model");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.01,or_greater"), "set_unit_size", "get_unit_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db");
@@ -843,7 +843,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,1,or_greater,exp"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,or_greater"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 814ed5c2a7..fd891a5e13 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -648,7 +648,7 @@ void CollisionObject3D::shape_owner_clear_shapes(uint32_t p_owner) {
}
uint32_t CollisionObject3D::shape_find_owner(int p_shape_index) const {
- ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0);
+ ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, UINT32_MAX);
for (const KeyValue<uint32_t, ShapeData> &E : shapes) {
for (int i = 0; i < E.value.shapes.size(); i++) {
@@ -659,7 +659,7 @@ uint32_t CollisionObject3D::shape_find_owner(int p_shape_index) const {
}
//in theory it should be unreachable
- return 0;
+ ERR_FAIL_V_MSG(UINT32_MAX, "Can't find owner for shape index " + itos(p_shape_index) + ".");
}
CollisionObject3D::CollisionObject3D(RID p_rid, bool p_area) {
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 160814ead4..aca7328a27 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -209,7 +209,6 @@ public:
void set_explosiveness_ratio(real_t p_ratio);
void set_randomness_ratio(real_t p_ratio);
void set_lifetime_randomness(double p_random);
- void set_visibility_aabb(const AABB &p_aabb);
void set_use_local_coordinates(bool p_enable);
void set_speed_scale(double p_scale);
@@ -221,7 +220,6 @@ public:
real_t get_explosiveness_ratio() const;
real_t get_randomness_ratio() const;
double get_lifetime_randomness() const;
- AABB get_visibility_aabb() const;
bool get_use_local_coordinates() const;
double get_speed_scale() const;
@@ -234,9 +232,6 @@ public:
void set_draw_order(DrawOrder p_order);
DrawOrder get_draw_order() const;
- void set_draw_passes(int p_count);
- int get_draw_passes() const;
-
void set_mesh(const Ref<Mesh> &p_mesh);
Ref<Mesh> get_mesh() const;
@@ -275,7 +270,6 @@ public:
void set_emission_points(const Vector<Vector3> &p_points);
void set_emission_normals(const Vector<Vector3> &p_normals);
void set_emission_colors(const Vector<Color> &p_colors);
- void set_emission_point_count(int p_count);
void set_emission_ring_axis(Vector3 p_axis);
void set_emission_ring_height(real_t p_height);
void set_emission_ring_radius(real_t p_radius);
@@ -291,7 +285,6 @@ public:
Vector<Vector3> get_emission_points() const;
Vector<Vector3> get_emission_normals() const;
Vector<Color> get_emission_colors() const;
- int get_emission_point_count() const;
Vector3 get_emission_ring_axis() const;
real_t get_emission_ring_height() const;
real_t get_emission_ring_radius() const;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 32a62d8c7e..ea6242b669 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -562,6 +562,7 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+ ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter");
ADD_GROUP("Time", "");
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index c2d5c757db..1bc7d20c19 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -192,7 +192,7 @@ Vector3 NavigationAgent3D::get_target_location() const {
Vector3 NavigationAgent3D::get_next_location() {
update_navigation();
if (navigation_path.size() == 0) {
- ERR_FAIL_COND_V(agent_parent == nullptr, Vector3());
+ ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector3(), "The agent has no parent.");
return agent_parent->get_global_transform().origin;
} else {
return navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0);
@@ -200,7 +200,7 @@ Vector3 NavigationAgent3D::get_next_location() {
}
real_t NavigationAgent3D::distance_to_target() const {
- ERR_FAIL_COND_V(agent_parent == nullptr, 0.0);
+ ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent.");
return agent_parent->get_global_transform().origin.distance_to(target_location);
}
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 8a51a259f7..473368cf69 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -162,7 +162,7 @@ void _bake_navigation_mesh(void *p_user_data) {
}
void NavigationRegion3D::bake_navigation_mesh() {
- ERR_FAIL_COND(bake_thread.is_started());
+ ERR_FAIL_COND_MSG(bake_thread.is_started(), "Unable to start another bake request. The navigation mesh bake thread is already baking a navigation mesh.");
BakeThreadsArgs *args = memnew(BakeThreadsArgs);
args->nav_region = this;
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index c96204cf60..5293dd3f0a 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -484,14 +484,14 @@ void Node3D::_update_gizmos() {
#endif
}
-#ifdef TOOLS_ENABLED
void Node3D::set_disable_gizmos(bool p_enabled) {
+#ifdef TOOLS_ENABLED
data.gizmos_disabled = p_enabled;
if (!p_enabled) {
clear_gizmos();
}
-}
#endif
+}
void Node3D::set_disable_scale(bool p_enabled) {
data.disable_scale = p_enabled;
diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp
index 9fceb21790..903eedb58b 100644
--- a/scene/3d/soft_dynamic_body_3d.cpp
+++ b/scene/3d/soft_dynamic_body_3d.cpp
@@ -250,7 +250,7 @@ void SoftDynamicBody3D::_notification(int p_what) {
RID space = get_world_3d()->get_space();
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space);
- prepare_physics_server();
+ _prepare_physics_server();
} break;
case NOTIFICATION_READY: {
@@ -284,13 +284,13 @@ void SoftDynamicBody3D::_notification(int p_what) {
case NOTIFICATION_DISABLED: {
if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) {
- prepare_physics_server();
+ _prepare_physics_server();
}
} break;
case NOTIFICATION_ENABLED: {
if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) {
- prepare_physics_server();
+ _prepare_physics_server();
}
} break;
@@ -378,7 +378,7 @@ void SoftDynamicBody3D::_bind_methods() {
TypedArray<String> SoftDynamicBody3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
- if (get_mesh().is_null()) {
+ if (mesh.is_null()) {
warnings.push_back(TTR("This body will be ignored until you set a mesh."));
}
@@ -407,11 +407,17 @@ void SoftDynamicBody3D::_update_physics_server() {
}
void SoftDynamicBody3D::_draw_soft_mesh() {
- if (get_mesh().is_null()) {
+ if (mesh.is_null()) {
return;
}
- const RID mesh_rid = get_mesh()->get_rid();
+ RID mesh_rid = mesh->get_rid();
+ if (owned_mesh != mesh_rid) {
+ _become_mesh_owner();
+ mesh_rid = mesh->get_rid();
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh_rid);
+ }
+
if (!rendering_server_handler.is_ready(mesh_rid)) {
rendering_server_handler.prepare(mesh_rid, 0);
@@ -430,11 +436,11 @@ void SoftDynamicBody3D::_draw_soft_mesh() {
rendering_server_handler.commit_changes();
}
-void SoftDynamicBody3D::prepare_physics_server() {
+void SoftDynamicBody3D::_prepare_physics_server() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- if (get_mesh().is_valid()) {
- PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()->get_rid());
+ if (mesh.is_valid()) {
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh->get_rid());
} else {
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID());
}
@@ -443,9 +449,13 @@ void SoftDynamicBody3D::prepare_physics_server() {
}
#endif
- if (get_mesh().is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) {
- become_mesh_owner();
- PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()->get_rid());
+ if (mesh.is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) {
+ RID mesh_rid = mesh->get_rid();
+ if (owned_mesh != mesh_rid) {
+ _become_mesh_owner();
+ mesh_rid = mesh->get_rid();
+ }
+ PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh_rid);
RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh));
} else {
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID());
@@ -455,38 +465,32 @@ void SoftDynamicBody3D::prepare_physics_server() {
}
}
-void SoftDynamicBody3D::become_mesh_owner() {
- if (mesh.is_null()) {
- return;
- }
+void SoftDynamicBody3D::_become_mesh_owner() {
+ Vector<Ref<Material>> copy_materials;
+ copy_materials.append_array(surface_override_materials);
- if (!mesh_owner) {
- mesh_owner = true;
+ ERR_FAIL_COND(!mesh->get_surface_count());
- Vector<Ref<Material>> copy_materials;
- copy_materials.append_array(surface_override_materials);
+ // Get current mesh array and create new mesh array with necessary flag for SoftDynamicBody
+ Array surface_arrays = mesh->surface_get_arrays(0);
+ Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
+ Dictionary surface_lods = mesh->surface_get_lods(0);
+ uint32_t surface_format = mesh->surface_get_format(0);
- ERR_FAIL_COND(!mesh->get_surface_count());
+ surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
- // Get current mesh array and create new mesh array with necessary flag for SoftDynamicBody
- Array surface_arrays = mesh->surface_get_arrays(0);
- Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
- Dictionary surface_lods = mesh->surface_get_lods(0);
- uint32_t surface_format = mesh->surface_get_format(0);
+ Ref<ArrayMesh> soft_mesh;
+ soft_mesh.instantiate();
+ soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format);
+ soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
- surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
+ set_mesh(soft_mesh);
- Ref<ArrayMesh> soft_mesh;
- soft_mesh.instantiate();
- soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format);
- soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
-
- set_mesh(soft_mesh);
-
- for (int i = copy_materials.size() - 1; 0 <= i; --i) {
- set_surface_override_material(i, copy_materials[i]);
- }
+ for (int i = copy_materials.size() - 1; 0 <= i; --i) {
+ set_surface_override_material(i, copy_materials[i]);
}
+
+ owned_mesh = soft_mesh->get_rid();
}
void SoftDynamicBody3D::set_collision_mask(uint32_t p_mask) {
@@ -548,16 +552,10 @@ void SoftDynamicBody3D::set_disable_mode(DisableMode p_mode) {
return;
}
- bool inside_tree = is_inside_tree();
-
- if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) {
- prepare_physics_server();
- }
-
disable_mode = p_mode;
- if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) {
- prepare_physics_server();
+ if (mesh.is_valid() && is_inside_tree() && !is_enabled()) {
+ _prepare_physics_server();
}
}
diff --git a/scene/3d/soft_dynamic_body_3d.h b/scene/3d/soft_dynamic_body_3d.h
index 5e7fbfe29e..57e116aa05 100644
--- a/scene/3d/soft_dynamic_body_3d.h
+++ b/scene/3d/soft_dynamic_body_3d.h
@@ -90,7 +90,7 @@ private:
DisableMode disable_mode = DISABLE_MODE_REMOVE;
- bool mesh_owner = false;
+ RID owned_mesh;
uint32_t collision_mask = 1;
uint32_t collision_layer = 1;
NodePath parent_collision_ignore;
@@ -106,6 +106,12 @@ private:
void _update_pickable();
+ void _update_physics_server();
+ void _draw_soft_mesh();
+
+ void _prepare_physics_server();
+ void _become_mesh_owner();
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -120,14 +126,7 @@ protected:
TypedArray<String> get_configuration_warnings() const override;
-protected:
- void _update_physics_server();
- void _draw_soft_mesh();
-
public:
- void prepare_physics_server();
- void become_mesh_owner();
-
RID get_physics_rid() const { return physics_rid; }
void set_collision_mask(uint32_t p_mask);
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 90c2a309e1..61448c0e32 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -118,12 +118,6 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
- void set_region_enabled(bool p_region);
- bool is_region_enabled() const;
-
- void set_region_rect(const Rect2 &p_region_rect);
- Rect2 get_region_rect() const;
-
void set_modulate(const Color &p_color);
Color get_modulate() const;
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 56edf100f6..9dbee58f0e 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -47,13 +47,45 @@ void XRCamera3D::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
// need to find our XROrigin3D parent and let it know we're no longer its camera!
XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin != nullptr) {
- origin->clear_tracked_camera_if(this);
+ if (origin != nullptr && origin->get_tracked_camera() == this) {
+ origin->set_tracked_camera(nullptr);
}
}; break;
};
};
+void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
+ if (p_tracker_name == tracker_name) {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ tracker = xr_server->get_tracker(p_tracker_name);
+ if (tracker.is_valid()) {
+ tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
+
+ Ref<XRPose> pose = tracker->get_pose(pose_name);
+ if (pose.is_valid()) {
+ set_transform(pose->get_adjusted_transform());
+ }
+ }
+ }
+}
+
+void XRCamera3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
+ if (p_tracker_name == tracker_name) {
+ if (tracker.is_valid()) {
+ tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
+ }
+ tracker.unref();
+ }
+}
+
+void XRCamera3D::_pose_changed(const Ref<XRPose> &p_pose) {
+ if (p_pose->get_name() == pose_name) {
+ set_transform(p_pose->get_adjusted_transform());
+ }
+}
+
TypedArray<String> XRCamera3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
@@ -172,195 +204,215 @@ Vector<Plane> XRCamera3D::get_frustum() const {
return cm.get_projection_planes(get_camera_transform());
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
+XRCamera3D::XRCamera3D() {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
-void XRController3D::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- set_process_internal(true);
- }; break;
- case NOTIFICATION_EXIT_TREE: {
- set_process_internal(false);
- }; break;
- case NOTIFICATION_INTERNAL_PROCESS: {
- // get our XRServer
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL(xr_server);
-
- // find the tracker for our controller
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (!tracker.is_valid()) {
- // this controller is currently turned off
- is_active = false;
- button_states = 0;
- } else {
- is_active = true;
- set_transform(tracker->get_transform(true));
-
- int joy_id = tracker->get_joy_id();
- if (joy_id >= 0) {
- int mask = 1;
- // check button states
- for (int i = 0; i < 16; i++) {
- bool was_pressed = (button_states & mask) == mask;
- bool is_pressed = Input::get_singleton()->is_joy_button_pressed(joy_id, (JoyButton)i);
-
- if (!was_pressed && is_pressed) {
- emit_signal(SNAME("button_pressed"), i);
- button_states += mask;
- } else if (was_pressed && !is_pressed) {
- emit_signal(SNAME("button_released"), i);
- button_states -= mask;
- };
-
- mask = mask << 1;
- };
-
- } else {
- button_states = 0;
- };
-
- // check for an updated mesh
- Ref<Mesh> trackerMesh = tracker->get_mesh();
- if (mesh != trackerMesh) {
- mesh = trackerMesh;
- emit_signal(SNAME("mesh_updated"), mesh);
- }
- };
- }; break;
- default:
- break;
- };
-};
+ xr_server->connect("tracker_added", callable_mp(this, &XRCamera3D::_changed_tracker));
+ xr_server->connect("tracker_updated", callable_mp(this, &XRCamera3D::_changed_tracker));
+ xr_server->connect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker));
+}
-void XRController3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_controller_id", "controller_id"), &XRController3D::set_controller_id);
- ClassDB::bind_method(D_METHOD("get_controller_id"), &XRController3D::get_controller_id);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_controller_id", "get_controller_id");
- ClassDB::bind_method(D_METHOD("get_controller_name"), &XRController3D::get_controller_name);
+XRCamera3D::~XRCamera3D() {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
- // passthroughs to information about our related joystick
- ClassDB::bind_method(D_METHOD("get_joystick_id"), &XRController3D::get_joystick_id);
- ClassDB::bind_method(D_METHOD("is_button_pressed", "button"), &XRController3D::is_button_pressed);
- ClassDB::bind_method(D_METHOD("get_joystick_axis", "axis"), &XRController3D::get_joystick_axis);
+ xr_server->disconnect("tracker_added", callable_mp(this, &XRCamera3D::_changed_tracker));
+ xr_server->disconnect("tracker_updated", callable_mp(this, &XRCamera3D::_changed_tracker));
+ xr_server->disconnect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker));
+}
- ClassDB::bind_method(D_METHOD("get_is_active"), &XRController3D::get_is_active);
- ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRController3D::get_tracker_hand);
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// XRNode3D is a node that has it's transform updated by an XRPositionalTracker.
+// Note that trackers are only available in runtime and only after an XRInterface registers one.
+// So we bind by name and as long as a tracker isn't available, our node remains inactive.
- ClassDB::bind_method(D_METHOD("get_rumble"), &XRController3D::get_rumble);
- ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRController3D::set_rumble);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble");
- ADD_PROPERTY_DEFAULT("rumble", 0.0);
+void XRNode3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_tracker", "tracker_name"), &XRNode3D::set_tracker);
+ ClassDB::bind_method(D_METHOD("get_tracker"), &XRNode3D::get_tracker);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "tracker", PROPERTY_HINT_ENUM_SUGGESTION), "set_tracker", "get_tracker");
- ClassDB::bind_method(D_METHOD("get_mesh"), &XRController3D::get_mesh);
+ ClassDB::bind_method(D_METHOD("set_pose_name", "pose"), &XRNode3D::set_pose_name);
+ ClassDB::bind_method(D_METHOD("get_pose_name"), &XRNode3D::get_pose_name);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "pose", PROPERTY_HINT_ENUM_SUGGESTION), "set_pose_name", "get_pose_name");
- ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button")));
- ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::INT, "button")));
- ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
+ ClassDB::bind_method(D_METHOD("get_is_active"), &XRNode3D::get_is_active);
+ ClassDB::bind_method(D_METHOD("get_has_tracking_data"), &XRNode3D::get_has_tracking_data);
+ ClassDB::bind_method(D_METHOD("get_pose"), &XRNode3D::get_pose);
+ ClassDB::bind_method(D_METHOD("trigger_haptic_pulse", "action_name", "frequency", "amplitude", "duration_sec", "delay_sec"), &XRNode3D::trigger_haptic_pulse);
};
-void XRController3D::set_controller_id(int p_controller_id) {
- // We don't check any bounds here, this controller may not yet be active and just be a place holder until it is.
- // Note that setting this to 0 means this node is not bound to a controller yet.
- controller_id = p_controller_id;
- update_configuration_warnings();
-};
+void XRNode3D::_validate_property(PropertyInfo &property) const {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
-int XRController3D::get_controller_id() const {
- return controller_id;
-};
+ if (property.name == "tracker") {
+ PackedStringArray names = xr_server->get_suggested_tracker_names();
+ String hint_string;
+ for (const String &name : names) {
+ hint_string += name + ",";
+ }
+ property.hint_string = hint_string;
+ } else if (property.name == "pose") {
+ PackedStringArray names = xr_server->get_suggested_pose_names(tracker_name);
+ String hint_string;
+ for (const String &name : names) {
+ hint_string += name + ",";
+ }
+ property.hint_string = hint_string;
+ }
+}
-String XRController3D::get_controller_name() const {
- // get our XRServer
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, String());
+void XRNode3D::set_tracker(const StringName p_tracker_name) {
+ if (tracker.is_valid() && tracker->get_tracker_name() == p_tracker_name) {
+ // didn't change
+ return;
+ }
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (!tracker.is_valid()) {
- return String("Not connected");
- };
+ // just in case
+ _unbind_tracker();
- return tracker->get_tracker_name();
-};
+ // copy the name
+ tracker_name = p_tracker_name;
+ pose_name = "default";
-int XRController3D::get_joystick_id() const {
- // get our XRServer
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, 0);
+ // see if it's already available
+ _bind_tracker();
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (!tracker.is_valid()) {
- // No tracker? no joystick id... (0 is our first joystick)
- return -1;
- };
+ update_configuration_warnings();
+ notify_property_list_changed();
+}
- return tracker->get_joy_id();
-};
+StringName XRNode3D::get_tracker() const {
+ return tracker_name;
+}
-bool XRController3D::is_button_pressed(int p_button) const {
- int joy_id = get_joystick_id();
- if (joy_id == -1) {
- return false;
- };
+void XRNode3D::set_pose_name(const StringName p_pose_name) {
+ pose_name = p_pose_name;
- return Input::get_singleton()->is_joy_button_pressed(joy_id, (JoyButton)p_button);
-};
+ // Update pose if we are bound to a tracker with a valid pose
+ Ref<XRPose> pose = get_pose();
+ if (pose.is_valid()) {
+ set_transform(pose->get_adjusted_transform());
+ }
+}
-float XRController3D::get_joystick_axis(int p_axis) const {
- int joy_id = get_joystick_id();
- if (joy_id == -1) {
- return 0.0;
- };
+StringName XRNode3D::get_pose_name() const {
+ return pose_name;
+}
- return Input::get_singleton()->get_joy_axis(joy_id, (JoyAxis)p_axis);
-};
+bool XRNode3D::get_is_active() const {
+ if (tracker.is_null()) {
+ return false;
+ } else if (!tracker->has_pose(pose_name)) {
+ return false;
+ } else {
+ return true;
+ }
+}
-real_t XRController3D::get_rumble() const {
- // get our XRServer
+bool XRNode3D::get_has_tracking_data() const {
+ if (tracker.is_null()) {
+ return false;
+ } else if (!tracker->has_pose(pose_name)) {
+ return false;
+ } else {
+ return tracker->get_pose(pose_name)->get_has_tracking_data();
+ }
+}
+
+void XRNode3D::trigger_haptic_pulse(const String &p_action_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
+ // TODO need to link trackers to the interface that registered them so we can call this on the correct interface.
+ // For now this works fine as in 99% of the cases we only have our primary interface active
XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, 0.0);
+ if (xr_server != nullptr) {
+ Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
+ if (xr_interface.is_valid()) {
+ xr_interface->trigger_haptic_pulse(p_action_name, tracker_name, p_frequency, p_amplitude, p_duration_sec, p_delay_sec);
+ }
+ }
+}
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (!tracker.is_valid()) {
- return 0.0;
- };
+Ref<XRPose> XRNode3D::get_pose() {
+ if (tracker.is_valid()) {
+ return tracker->get_pose(pose_name);
+ } else {
+ return Ref<XRPose>();
+ }
+}
- return tracker->get_rumble();
-};
+void XRNode3D::_bind_tracker() {
+ ERR_FAIL_COND_MSG(tracker.is_valid(), "Unbind the current tracker first");
-void XRController3D::set_rumble(real_t p_rumble) {
- // get our XRServer
XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL(xr_server);
+ if (xr_server != nullptr) {
+ tracker = xr_server->get_tracker(tracker_name);
+ if (tracker.is_null()) {
+ // It is possible and valid if the tracker isn't available (yet), in this case we just exit
+ return;
+ }
+
+ tracker->connect("pose_changed", callable_mp(this, &XRNode3D::_pose_changed));
+
+ Ref<XRPose> pose = get_pose();
+ if (pose.is_valid()) {
+ set_transform(pose->get_adjusted_transform());
+ }
+ }
+}
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+void XRNode3D::_unbind_tracker() {
if (tracker.is_valid()) {
- tracker->set_rumble(p_rumble);
- };
-};
+ tracker->disconnect("pose_changed", callable_mp(this, &XRNode3D::_pose_changed));
-Ref<Mesh> XRController3D::get_mesh() const {
- return mesh;
+ tracker.unref();
+ }
}
-bool XRController3D::get_is_active() const {
- return is_active;
-};
+void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
+ if (p_tracker_name == p_tracker_name) {
+ // just in case unref our current tracker
+ _unbind_tracker();
-XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {
- // get our XRServer
+ // get our new tracker
+ _bind_tracker();
+ }
+}
+
+void XRNode3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
+ if (p_tracker_name == p_tracker_name) {
+ // unref our tracker, it's no longer available
+ _unbind_tracker();
+ }
+}
+
+void XRNode3D::_pose_changed(const Ref<XRPose> &p_pose) {
+ if (p_pose.is_valid() && p_pose->get_name() == pose_name) {
+ set_transform(p_pose->get_adjusted_transform());
+ }
+}
+
+XRNode3D::XRNode3D() {
XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, XRPositionalTracker::TRACKER_HAND_UNKNOWN);
+ ERR_FAIL_NULL(xr_server);
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (!tracker.is_valid()) {
- return XRPositionalTracker::TRACKER_HAND_UNKNOWN;
- };
+ xr_server->connect("tracker_added", callable_mp(this, &XRNode3D::_changed_tracker));
+ xr_server->connect("tracker_updated", callable_mp(this, &XRNode3D::_changed_tracker));
+ xr_server->connect("tracker_removed", callable_mp(this, &XRNode3D::_removed_tracker));
+}
- return tracker->get_tracker_hand();
-};
+XRNode3D::~XRNode3D() {
+ _unbind_tracker();
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
+
+ xr_server->disconnect("tracker_added", callable_mp(this, &XRNode3D::_changed_tracker));
+ xr_server->disconnect("tracker_updated", callable_mp(this, &XRNode3D::_changed_tracker));
+ xr_server->disconnect("tracker_removed", callable_mp(this, &XRNode3D::_removed_tracker));
+}
-TypedArray<String> XRController3D::get_configuration_warnings() const {
+TypedArray<String> XRNode3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
@@ -370,130 +422,171 @@ TypedArray<String> XRController3D::get_configuration_warnings() const {
warnings.push_back(TTR("XRController3D must have an XROrigin3D node as its parent."));
}
- if (controller_id == 0) {
- warnings.push_back(TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."));
+ if (tracker_name == "") {
+ warnings.push_back(TTR("No tracker name is set."));
+ }
+
+ if (pose_name == "") {
+ warnings.push_back(TTR("No pose is set."));
}
}
return warnings;
-};
+}
////////////////////////////////////////////////////////////////////////////////////////////////////
-void XRAnchor3D::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- set_process_internal(true);
- }; break;
- case NOTIFICATION_EXIT_TREE: {
- set_process_internal(false);
- }; break;
- case NOTIFICATION_INTERNAL_PROCESS: {
- // get our XRServer
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL(xr_server);
-
- // find the tracker for our anchor
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
- if (!tracker.is_valid()) {
- // this anchor is currently not available
- is_active = false;
- } else {
- is_active = true;
- Transform3D transform;
-
- // we'll need our world_scale
- real_t world_scale = xr_server->get_world_scale();
-
- // get our info from our tracker
- transform.basis = tracker->get_orientation();
- transform.origin = tracker->get_position(); // <-- already adjusted to world scale
-
- // our basis is scaled to the size of the plane the anchor is tracking
- // extract the size from our basis and reset the scale
- size = transform.basis.get_scale() * world_scale;
- transform.basis.orthonormalize();
-
- // apply our reference frame and set our transform
- set_transform(xr_server->get_reference_frame() * transform);
-
- // check for an updated mesh
- Ref<Mesh> trackerMesh = tracker->get_mesh();
- if (mesh != trackerMesh) {
- mesh = trackerMesh;
- emit_signal(SNAME("mesh_updated"), mesh);
- }
- };
- }; break;
- default:
- break;
- };
-};
-
-void XRAnchor3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_anchor_id", "anchor_id"), &XRAnchor3D::set_anchor_id);
- ClassDB::bind_method(D_METHOD("get_anchor_id"), &XRAnchor3D::get_anchor_id);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_anchor_id", "get_anchor_id");
- ClassDB::bind_method(D_METHOD("get_anchor_name"), &XRAnchor3D::get_anchor_name);
+void XRController3D::_bind_methods() {
+ // passthroughs to information about our related joystick
+ ClassDB::bind_method(D_METHOD("is_button_pressed", "name"), &XRController3D::is_button_pressed);
+ ClassDB::bind_method(D_METHOD("get_value", "name"), &XRController3D::get_value);
+ ClassDB::bind_method(D_METHOD("get_axis", "name"), &XRController3D::get_axis);
- ClassDB::bind_method(D_METHOD("get_is_active"), &XRAnchor3D::get_is_active);
- ClassDB::bind_method(D_METHOD("get_size"), &XRAnchor3D::get_size);
+ ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRController3D::get_tracker_hand);
- ClassDB::bind_method(D_METHOD("get_plane"), &XRAnchor3D::get_plane);
+ ClassDB::bind_method(D_METHOD("get_rumble"), &XRController3D::get_rumble);
+ ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRController3D::set_rumble);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble");
+ ADD_PROPERTY_DEFAULT("rumble", 0.0);
- ClassDB::bind_method(D_METHOD("get_mesh"), &XRAnchor3D::get_mesh);
- ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
+ ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::STRING, "name")));
+ ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name")));
+ ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value")));
+ ADD_SIGNAL(MethodInfo("input_axis_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "value")));
};
-void XRAnchor3D::set_anchor_id(int p_anchor_id) {
- // We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
- // Note that setting this to 0 means this node is not bound to an anchor yet.
- anchor_id = p_anchor_id;
- update_configuration_warnings();
-};
+void XRController3D::_bind_tracker() {
+ XRNode3D::_bind_tracker();
+ if (tracker.is_valid()) {
+ // bind to input signals
+ tracker->connect("button_pressed", callable_mp(this, &XRController3D::_button_pressed));
+ tracker->connect("button_released", callable_mp(this, &XRController3D::_button_released));
+ tracker->connect("input_value_changed", callable_mp(this, &XRController3D::_input_value_changed));
+ tracker->connect("input_axis_changed", callable_mp(this, &XRController3D::_input_axis_changed));
+ }
+}
-int XRAnchor3D::get_anchor_id() const {
- return anchor_id;
-};
+void XRController3D::_unbind_tracker() {
+ if (tracker.is_valid()) {
+ // unbind input signals
+ tracker->disconnect("button_pressed", callable_mp(this, &XRController3D::_button_pressed));
+ tracker->disconnect("button_released", callable_mp(this, &XRController3D::_button_released));
+ tracker->disconnect("input_value_changed", callable_mp(this, &XRController3D::_input_value_changed));
+ tracker->disconnect("input_axis_changed", callable_mp(this, &XRController3D::_input_axis_changed));
+ }
-Vector3 XRAnchor3D::get_size() const {
- return size;
-};
+ XRNode3D::_unbind_tracker();
+}
-String XRAnchor3D::get_anchor_name() const {
- // get our XRServer
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, String());
+void XRController3D::_button_pressed(const String &p_name) {
+ // just pass it on...
+ emit_signal("button_pressed", p_name);
+}
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
- if (!tracker.is_valid()) {
- return String("Not connected");
- };
+void XRController3D::_button_released(const String &p_name) {
+ // just pass it on...
+ emit_signal("button_released", p_name);
+}
- return tracker->get_tracker_name();
-};
+void XRController3D::_input_value_changed(const String &p_name, float p_value) {
+ // just pass it on...
+ emit_signal("input_value_changed", p_name, p_value);
+}
-bool XRAnchor3D::get_is_active() const {
- return is_active;
-};
+void XRController3D::_input_axis_changed(const String &p_name, Vector2 p_value) {
+ // just pass it on...
+ emit_signal("input_axis_changed", p_name, p_value);
+}
-TypedArray<String> XRAnchor3D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
+bool XRController3D::is_button_pressed(const StringName &p_name) const {
+ if (tracker.is_valid()) {
+ // Inputs should already be of the correct type, our XR runtime handles conversions between raw input and the desired type
+ bool pressed = tracker->get_input(p_name);
+ return pressed;
+ } else {
+ return false;
+ }
+}
- if (is_visible() && is_inside_tree()) {
- // must be child node of XROrigin3D!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- warnings.push_back(TTR("XRAnchor3D must have an XROrigin3D node as its parent."));
- }
+float XRController3D::get_value(const StringName &p_name) const {
+ if (tracker.is_valid()) {
+ // Inputs should already be of the correct type, our XR runtime handles conversions between raw input and the desired type, but just in case we convert
+ Variant input = tracker->get_input(p_name);
+ switch (input.get_type()) {
+ case Variant::BOOL: {
+ bool value = input;
+ return value ? 1.0 : 0.0;
+ } break;
+ case Variant::FLOAT: {
+ float value = input;
+ return value;
+ } break;
+ default:
+ return 0.0;
+ };
+ } else {
+ return 0.0;
+ }
+}
- if (anchor_id == 0) {
- warnings.push_back(TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."));
+Vector2 XRController3D::get_axis(const StringName &p_name) const {
+ if (tracker.is_valid()) {
+ // Inputs should already be of the correct type, our XR runtime handles conversions between raw input and the desired type, but just in case we convert
+ Variant input = tracker->get_input(p_name);
+ switch (input.get_type()) {
+ case Variant::BOOL: {
+ bool value = input;
+ return Vector2(value ? 1.0 : 0.0, 0.0);
+ } break;
+ case Variant::FLOAT: {
+ float value = input;
+ return Vector2(value, 0.0);
+ } break;
+ case Variant::VECTOR2: {
+ Vector2 axis = input;
+ return axis;
+ }
+ default:
+ return Vector2();
}
+ } else {
+ return Vector2();
}
+}
- return warnings;
-};
+real_t XRController3D::get_rumble() const {
+ if (!tracker.is_valid()) {
+ return 0.0;
+ }
+
+ return tracker->get_rumble();
+}
+
+void XRController3D::set_rumble(real_t p_rumble) {
+ if (tracker.is_valid()) {
+ tracker->set_rumble(p_rumble);
+ }
+}
+
+XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {
+ // get our XRServer
+ if (!tracker.is_valid()) {
+ return XRPositionalTracker::TRACKER_HAND_UNKNOWN;
+ }
+
+ return tracker->get_tracker_hand();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void XRAnchor3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_size"), &XRAnchor3D::get_size);
+ ClassDB::bind_method(D_METHOD("get_plane"), &XRAnchor3D::get_plane);
+}
+
+Vector3 XRAnchor3D::get_size() const {
+ return size;
+}
Plane XRAnchor3D::get_plane() const {
Vector3 location = get_position();
@@ -502,10 +595,6 @@ Plane XRAnchor3D::get_plane() const {
Plane plane(orientation.get_axis(1).normalized(), location);
return plane;
-};
-
-Ref<Mesh> XRAnchor3D::get_mesh() const {
- return mesh;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -525,23 +614,21 @@ TypedArray<String> XROrigin3D::get_configuration_warnings() const {
}
return warnings;
-};
+}
void XROrigin3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &XROrigin3D::set_world_scale);
ClassDB::bind_method(D_METHOD("get_world_scale"), &XROrigin3D::get_world_scale);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
-};
+}
void XROrigin3D::set_tracked_camera(XRCamera3D *p_tracked_camera) {
tracked_camera = p_tracked_camera;
-};
+}
-void XROrigin3D::clear_tracked_camera_if(XRCamera3D *p_tracked_camera) {
- if (tracked_camera == p_tracked_camera) {
- tracked_camera = nullptr;
- };
-};
+XRCamera3D *XROrigin3D::get_tracked_camera() const {
+ return tracked_camera;
+}
real_t XROrigin3D::get_world_scale() const {
// get our XRServer
@@ -549,7 +636,7 @@ real_t XROrigin3D::get_world_scale() const {
ERR_FAIL_NULL_V(xr_server, 1.0);
return xr_server->get_world_scale();
-};
+}
void XROrigin3D::set_world_scale(real_t p_world_scale) {
// get our XRServer
@@ -557,7 +644,7 @@ void XROrigin3D::set_world_scale(real_t p_world_scale) {
ERR_FAIL_NULL(xr_server);
xr_server->set_world_scale(p_world_scale);
-};
+}
void XROrigin3D::_notification(int p_what) {
// get our XRServer
@@ -596,4 +683,4 @@ void XROrigin3D::_notification(int p_what) {
interface->notification(p_what);
}
}
-};
+}
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index 6e54ff83d7..5e7d06093d 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -45,8 +45,18 @@ class XRCamera3D : public Camera3D {
GDCLASS(XRCamera3D, Camera3D);
protected:
+ // The name and pose for our HMD tracker is currently the only hardcoded bit.
+ // If we ever are able to support multiple HMDs we may need to make this settable.
+ StringName tracker_name = "head";
+ StringName pose_name = "default";
+ Ref<XRPositionalTracker> tracker;
+
void _notification(int p_what);
+ void _changed_tracker(const StringName p_tracker_name, int p_tracker_type);
+ void _removed_tracker(const StringName p_tracker_name, int p_tracker_type);
+ void _pose_changed(const Ref<XRPose> &p_pose);
+
public:
TypedArray<String> get_configuration_warnings() const override;
@@ -55,48 +65,88 @@ public:
virtual Vector3 project_position(const Point2 &p_point, real_t p_z_depth) const override;
virtual Vector<Plane> get_frustum() const override;
- XRCamera3D() {}
- ~XRCamera3D() {}
+ XRCamera3D();
+ ~XRCamera3D();
};
/*
- XRController3D is a helper node that automatically updates its position based on tracker data.
+ XRNode3D is a helper node that implements binding to a tracker.
It must be a child node of our XROrigin node
*/
-class XRController3D : public Node3D {
- GDCLASS(XRController3D, Node3D);
+class XRNode3D : public Node3D {
+ GDCLASS(XRNode3D, Node3D);
private:
- int controller_id = 1;
+ StringName tracker_name;
+ StringName pose_name = "default";
bool is_active = true;
- int button_states = 0;
- Ref<Mesh> mesh;
protected:
- void _notification(int p_what);
+ Ref<XRPositionalTracker> tracker;
+
static void _bind_methods();
-public:
- void set_controller_id(int p_controller_id);
- int get_controller_id() const;
- String get_controller_name() const;
+ virtual void _bind_tracker();
+ virtual void _unbind_tracker();
+ void _changed_tracker(const StringName p_tracker_name, int p_tracker_type);
+ void _removed_tracker(const StringName p_tracker_name, int p_tracker_type);
- int get_joystick_id() const;
- bool is_button_pressed(int p_button) const;
- float get_joystick_axis(int p_axis) const;
+ void _pose_changed(const Ref<XRPose> &p_pose);
- real_t get_rumble() const;
- void set_rumble(real_t p_rumble);
+public:
+ virtual void _validate_property(PropertyInfo &property) const override;
+ void set_tracker(const StringName p_tracker_name);
+ StringName get_tracker() const;
+
+ void set_pose_name(const StringName p_pose);
+ StringName get_pose_name() const;
bool get_is_active() const;
- XRPositionalTracker::TrackerHand get_tracker_hand() const;
+ bool get_has_tracking_data() const;
- Ref<Mesh> get_mesh() const;
+ void trigger_haptic_pulse(const String &p_action_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0);
+
+ Ref<XRPose> get_pose();
TypedArray<String> get_configuration_warnings() const override;
+ XRNode3D();
+ ~XRNode3D();
+};
+
+/*
+ XRController3D is a helper node that automatically updates its position based on tracker data.
+
+ It must be a child node of our XROrigin node
+*/
+
+class XRController3D : public XRNode3D {
+ GDCLASS(XRController3D, XRNode3D);
+
+private:
+protected:
+ static void _bind_methods();
+
+ virtual void _bind_tracker() override;
+ virtual void _unbind_tracker() override;
+
+ void _button_pressed(const String &p_name);
+ void _button_released(const String &p_name);
+ void _input_value_changed(const String &p_name, float p_value);
+ void _input_axis_changed(const String &p_name, Vector2 p_value);
+
+public:
+ bool is_button_pressed(const StringName &p_name) const;
+ float get_value(const StringName &p_name) const;
+ Vector2 get_axis(const StringName &p_name) const;
+
+ real_t get_rumble() const;
+ void set_rumble(real_t p_rumble);
+
+ XRPositionalTracker::TrackerHand get_tracker_hand() const;
+
XRController3D() {}
~XRController3D() {}
};
@@ -106,33 +156,19 @@ public:
It must be a child node of our XROrigin3D node
*/
-class XRAnchor3D : public Node3D {
- GDCLASS(XRAnchor3D, Node3D);
+class XRAnchor3D : public XRNode3D {
+ GDCLASS(XRAnchor3D, XRNode3D);
private:
- int anchor_id = 1;
- bool is_active = true;
Vector3 size;
- Ref<Mesh> mesh;
protected:
- void _notification(int p_what);
static void _bind_methods();
public:
- void set_anchor_id(int p_anchor_id);
- int get_anchor_id() const;
- String get_anchor_name() const;
-
- bool get_is_active() const;
Vector3 get_size() const;
-
Plane get_plane() const;
- Ref<Mesh> get_mesh() const;
-
- TypedArray<String> get_configuration_warnings() const override;
-
XRAnchor3D() {}
~XRAnchor3D() {}
};
@@ -159,7 +195,7 @@ public:
TypedArray<String> get_configuration_warnings() const override;
void set_tracked_camera(XRCamera3D *p_tracked_camera);
- void clear_tracked_camera_if(XRCamera3D *p_tracked_camera);
+ XRCamera3D *get_tracked_camera() const;
real_t get_world_scale() const;
void set_world_scale(real_t p_world_scale);