Merge pull request #63607 from BastiaanOlij/fix_xr_origin
Add current setting to XROrigin3D and fix double positioning HMD
This commit is contained in:
commit
5f4aa11c62
3 changed files with 118 additions and 65 deletions
|
@ -13,6 +13,9 @@
|
||||||
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
|
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<members>
|
<members>
|
||||||
|
<member name="current" type="bool" setter="set_current" getter="is_current" default="false">
|
||||||
|
Is this XROrigin3D node the current origin used by the [XRServer]?
|
||||||
|
</member>
|
||||||
<member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
|
<member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
|
||||||
Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
|
Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
|
||||||
[b]Note:[/b] This method is a passthrough to the [XRServer] itself.
|
[b]Note:[/b] This method is a passthrough to the [XRServer] itself.
|
||||||
|
|
|
@ -36,49 +36,37 @@
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void XRCamera3D::_notification(int p_what) {
|
void XRCamera3D::_bind_tracker() {
|
||||||
switch (p_what) {
|
XRServer *xr_server = XRServer::get_singleton();
|
||||||
case NOTIFICATION_ENTER_TREE: {
|
ERR_FAIL_NULL(xr_server);
|
||||||
// need to find our XROrigin3D parent and let it know we're its camera!
|
|
||||||
XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
|
|
||||||
if (origin != nullptr) {
|
|
||||||
origin->set_tracked_camera(this);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case NOTIFICATION_EXIT_TREE: {
|
tracker = xr_server->get_tracker(tracker_name);
|
||||||
// need to find our XROrigin3D parent and let it know we're no longer its camera!
|
if (tracker.is_valid()) {
|
||||||
XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
|
tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
|
||||||
if (origin != nullptr && origin->get_tracked_camera() == this) {
|
|
||||||
origin->set_tracked_camera(nullptr);
|
Ref<XRPose> pose = tracker->get_pose(pose_name);
|
||||||
}
|
if (pose.is_valid()) {
|
||||||
} break;
|
set_transform(pose->get_adjusted_transform());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XRCamera3D::_unbind_tracker() {
|
||||||
|
if (tracker.is_valid()) {
|
||||||
|
tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
|
||||||
|
}
|
||||||
|
tracker.unref();
|
||||||
|
}
|
||||||
|
|
||||||
void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
|
void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
|
||||||
if (p_tracker_name == tracker_name) {
|
if (p_tracker_name == tracker_name) {
|
||||||
XRServer *xr_server = XRServer::get_singleton();
|
_bind_tracker();
|
||||||
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) {
|
void XRCamera3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
|
||||||
if (p_tracker_name == tracker_name) {
|
if (p_tracker_name == tracker_name) {
|
||||||
if (tracker.is_valid()) {
|
_unbind_tracker();
|
||||||
tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
|
|
||||||
}
|
|
||||||
tracker.unref();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +201,9 @@ XRCamera3D::XRCamera3D() {
|
||||||
xr_server->connect("tracker_added", callable_mp(this, &XRCamera3D::_changed_tracker));
|
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_updated", callable_mp(this, &XRCamera3D::_changed_tracker));
|
||||||
xr_server->connect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker));
|
xr_server->connect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker));
|
||||||
|
|
||||||
|
// check if our tracker already exists and if so, bind it...
|
||||||
|
_bind_tracker();
|
||||||
}
|
}
|
||||||
|
|
||||||
XRCamera3D::~XRCamera3D() {
|
XRCamera3D::~XRCamera3D() {
|
||||||
|
@ -582,11 +573,22 @@ Plane XRAnchor3D::get_plane() const {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Vector<XROrigin3D *> XROrigin3D::origin_nodes;
|
||||||
|
|
||||||
PackedStringArray XROrigin3D::get_configuration_warnings() const {
|
PackedStringArray XROrigin3D::get_configuration_warnings() const {
|
||||||
PackedStringArray warnings = Node::get_configuration_warnings();
|
PackedStringArray warnings = Node::get_configuration_warnings();
|
||||||
|
|
||||||
if (is_visible() && is_inside_tree()) {
|
if (is_visible() && is_inside_tree()) {
|
||||||
if (tracked_camera == nullptr) {
|
bool has_camera = false;
|
||||||
|
for (int i = 0; !has_camera && i < get_child_count(); i++) {
|
||||||
|
XRCamera3D *camera = Object::cast_to<XRCamera3D>(get_child(i));
|
||||||
|
if (camera) {
|
||||||
|
// found it!
|
||||||
|
has_camera = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_camera) {
|
||||||
warnings.push_back(RTR("XROrigin3D requires an XRCamera3D child node."));
|
warnings.push_back(RTR("XROrigin3D requires an XRCamera3D child node."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,14 +605,10 @@ void XROrigin3D::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &XROrigin3D::set_world_scale);
|
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);
|
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");
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
|
||||||
}
|
|
||||||
|
|
||||||
void XROrigin3D::set_tracked_camera(XRCamera3D *p_tracked_camera) {
|
ClassDB::bind_method(D_METHOD("set_current", "enabled"), &XROrigin3D::set_current);
|
||||||
tracked_camera = p_tracked_camera;
|
ClassDB::bind_method(D_METHOD("is_current"), &XROrigin3D::is_current);
|
||||||
}
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
|
||||||
|
|
||||||
XRCamera3D *XROrigin3D::get_tracked_camera() const {
|
|
||||||
return tracked_camera;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
real_t XROrigin3D::get_world_scale() const {
|
real_t XROrigin3D::get_world_scale() const {
|
||||||
|
@ -629,6 +627,44 @@ void XROrigin3D::set_world_scale(real_t p_world_scale) {
|
||||||
xr_server->set_world_scale(p_world_scale);
|
xr_server->set_world_scale(p_world_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XROrigin3D::set_current(bool p_enabled) {
|
||||||
|
current = p_enabled;
|
||||||
|
|
||||||
|
if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify us of any transform changes
|
||||||
|
set_notify_local_transform(current);
|
||||||
|
set_notify_transform(current);
|
||||||
|
|
||||||
|
if (current) {
|
||||||
|
for (int i = 0; i < origin_nodes.size(); i++) {
|
||||||
|
if (origin_nodes[i] != this) {
|
||||||
|
origin_nodes[i]->set_current(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bool found = false;
|
||||||
|
// We no longer have a current origin so find the first one we can make current
|
||||||
|
for (int i = 0; !found && i < origin_nodes.size(); i++) {
|
||||||
|
if (origin_nodes[i] != this) {
|
||||||
|
origin_nodes[i]->set_current(true);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XROrigin3D::is_current() const {
|
||||||
|
if (Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
// return as is
|
||||||
|
return current;
|
||||||
|
} else {
|
||||||
|
return current && is_inside_tree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void XROrigin3D::_notification(int p_what) {
|
void XROrigin3D::_notification(int p_what) {
|
||||||
// get our XRServer
|
// get our XRServer
|
||||||
XRServer *xr_server = XRServer::get_singleton();
|
XRServer *xr_server = XRServer::get_singleton();
|
||||||
|
@ -636,34 +672,47 @@ void XROrigin3D::_notification(int p_what) {
|
||||||
|
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case NOTIFICATION_ENTER_TREE: {
|
case NOTIFICATION_ENTER_TREE: {
|
||||||
set_process_internal(true);
|
if (!Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
if (origin_nodes.is_empty()) {
|
||||||
|
// first entry always becomes current
|
||||||
|
current = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
origin_nodes.push_back(this);
|
||||||
|
|
||||||
|
if (current) {
|
||||||
|
// set this again so we do whatever setup is needed.
|
||||||
|
set_current(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_EXIT_TREE: {
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
set_process_internal(false);
|
if (!Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
origin_nodes.erase(this);
|
||||||
|
|
||||||
|
if (current) {
|
||||||
|
// We are no longer current
|
||||||
|
set_current(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_INTERNAL_PROCESS: {
|
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED:
|
||||||
// set our world origin to our node transform
|
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||||
xr_server->set_world_origin(get_global_transform());
|
if (current && !Engine::get_singleton()->is_editor_hint()) {
|
||||||
|
xr_server->set_world_origin(get_global_transform());
|
||||||
// check if we have a primary interface
|
|
||||||
Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
|
|
||||||
if (xr_interface.is_valid() && tracked_camera != nullptr) {
|
|
||||||
// get our positioning transform for our headset
|
|
||||||
Transform3D t = xr_interface->get_camera_transform();
|
|
||||||
|
|
||||||
// now apply this to our camera
|
|
||||||
tracked_camera->set_transform(t);
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send our notification to all active XE interfaces, they may need to react to it also
|
if (current) {
|
||||||
for (int i = 0; i < xr_server->get_interface_count(); i++) {
|
// send our notification to all active XE interfaces, they may need to react to it also
|
||||||
Ref<XRInterface> interface = xr_server->get_interface(i);
|
for (int i = 0; i < xr_server->get_interface_count(); i++) {
|
||||||
if (interface.is_valid() && interface->is_initialized()) {
|
Ref<XRInterface> interface = xr_server->get_interface(i);
|
||||||
interface->notification(p_what);
|
if (interface.is_valid() && interface->is_initialized()) {
|
||||||
|
interface->notification(p_what);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,8 @@ protected:
|
||||||
StringName pose_name = "default";
|
StringName pose_name = "default";
|
||||||
Ref<XRPositionalTracker> tracker;
|
Ref<XRPositionalTracker> tracker;
|
||||||
|
|
||||||
void _notification(int p_what);
|
void _bind_tracker();
|
||||||
|
void _unbind_tracker();
|
||||||
void _changed_tracker(const StringName p_tracker_name, int p_tracker_type);
|
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 _removed_tracker(const StringName p_tracker_name, int p_tracker_type);
|
||||||
void _pose_changed(const Ref<XRPose> &p_pose);
|
void _pose_changed(const Ref<XRPose> &p_pose);
|
||||||
|
@ -180,7 +180,8 @@ class XROrigin3D : public Node3D {
|
||||||
GDCLASS(XROrigin3D, Node3D);
|
GDCLASS(XROrigin3D, Node3D);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XRCamera3D *tracked_camera = nullptr;
|
bool current = false;
|
||||||
|
static Vector<XROrigin3D *> origin_nodes; // all origin nodes in tree
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
@ -189,12 +190,12 @@ protected:
|
||||||
public:
|
public:
|
||||||
PackedStringArray get_configuration_warnings() const override;
|
PackedStringArray get_configuration_warnings() const override;
|
||||||
|
|
||||||
void set_tracked_camera(XRCamera3D *p_tracked_camera);
|
|
||||||
XRCamera3D *get_tracked_camera() const;
|
|
||||||
|
|
||||||
real_t get_world_scale() const;
|
real_t get_world_scale() const;
|
||||||
void set_world_scale(real_t p_world_scale);
|
void set_world_scale(real_t p_world_scale);
|
||||||
|
|
||||||
|
void set_current(bool p_enabled);
|
||||||
|
bool is_current() const;
|
||||||
|
|
||||||
XROrigin3D() {}
|
XROrigin3D() {}
|
||||||
~XROrigin3D() {}
|
~XROrigin3D() {}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue