Merge pull request #49942 from BastiaanOlij/xr_play_area
Add support for returning the play area from XRInterface
This commit is contained in:
commit
964c8322b1
10 changed files with 229 additions and 28 deletions
|
@ -29,6 +29,12 @@
|
|||
Returns the name of this interface (OpenXR, OpenVR, OpenHMD, ARKit, etc).
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_play_area" qualifiers="const">
|
||||
<return type="PackedVector3Array" />
|
||||
<description>
|
||||
Returns an array of vectors that denotes the physical play area mapped to the virtual space around the [XROrigin3D] point. The points form a convex polygon that can be used to react to or visualise the play area. This returns an empty array if this feature is not supported or if the information is not yet available.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_render_target_size">
|
||||
<return type="Vector2" />
|
||||
<description>
|
||||
|
@ -63,6 +69,20 @@
|
|||
Is [code]true[/code] if this interface has been initialised.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_play_area_mode">
|
||||
<return type="bool" />
|
||||
<argument index="0" name="mode" type="int" enum="XRInterface.PlayAreaMode" />
|
||||
<description>
|
||||
Sets the active play area mode, will return [code]false[/code] if the mode can't be used with this interface.
|
||||
</description>
|
||||
</method>
|
||||
<method name="supports_play_area_mode">
|
||||
<return type="bool" />
|
||||
<argument index="0" name="mode" type="int" enum="XRInterface.PlayAreaMode" />
|
||||
<description>
|
||||
Call this to find out if a given play area mode is supported by this interface.
|
||||
</description>
|
||||
</method>
|
||||
<method name="trigger_haptic_pulse">
|
||||
<return type="void" />
|
||||
<argument index="0" name="action_name" type="String" />
|
||||
|
@ -91,7 +111,18 @@
|
|||
<member name="interface_is_primary" type="bool" setter="set_primary" getter="is_primary" default="false">
|
||||
[code]true[/code] if this is the primary interface.
|
||||
</member>
|
||||
<member name="xr_play_area_mode" type="int" setter="set_play_area_mode" getter="get_play_area_mode" enum="XRInterface.PlayAreaMode" default="0">
|
||||
The play area mode for this interface.
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="play_area_changed">
|
||||
<argument index="0" name="mode" type="int" />
|
||||
<description>
|
||||
Emitted when the play area is changed. This can be a result of the player resetting the boundary or entering a new play area, the player changing the play area mode, the world scale changing or the player resetting their headset orientation.
|
||||
</description>
|
||||
</signal>
|
||||
</signals>
|
||||
<constants>
|
||||
<constant name="XR_NONE" value="0" enum="Capabilities">
|
||||
No XR capabilities.
|
||||
|
@ -129,5 +160,20 @@
|
|||
<constant name="XR_NOT_TRACKING" value="4" enum="TrackingStatus">
|
||||
Tracking is not functional (camera not plugged in or obscured, lighthouses turned off, etc.).
|
||||
</constant>
|
||||
<constant name="XR_PLAY_AREA_UNKNOWN" value="0" enum="PlayAreaMode">
|
||||
Play area mode not set or not available.
|
||||
</constant>
|
||||
<constant name="XR_PLAY_AREA_3DOF" value="1" enum="PlayAreaMode">
|
||||
Play area only supports orientation tracking, no positional tracking, area will center around player.
|
||||
</constant>
|
||||
<constant name="XR_PLAY_AREA_SITTING" value="2" enum="PlayAreaMode">
|
||||
Player is in seated position, limited positional tracking, fixed guardian around player.
|
||||
</constant>
|
||||
<constant name="XR_PLAY_AREA_ROOMSCALE" value="3" enum="PlayAreaMode">
|
||||
Player is free to move around, full positional tracking.
|
||||
</constant>
|
||||
<constant name="XR_PLAY_AREA_STAGE" value="4" enum="PlayAreaMode">
|
||||
Same as roomscale but origin point is fixed to the center of the physical space, XRServer.center_on_hmd disabled.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
@ -41,6 +41,16 @@
|
|||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_play_area" qualifiers="virtual const">
|
||||
<return type="PackedVector3Array" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_play_area_mode" qualifiers="virtual const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_projection_for_view" qualifiers="virtual">
|
||||
<return type="PackedFloat64Array" />
|
||||
<argument index="0" name="view" type="int" />
|
||||
|
@ -71,6 +81,11 @@
|
|||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_tracking_status" qualifiers="virtual const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_get_transform_for_view" qualifiers="virtual">
|
||||
<return type="Transform3D" />
|
||||
<argument index="0" name="view" type="int" />
|
||||
|
@ -110,6 +125,18 @@
|
|||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_set_play_area_mode" qualifiers="virtual const">
|
||||
<return type="bool" />
|
||||
<argument index="0" name="mode" type="int" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_supports_play_area_mode" qualifiers="virtual const">
|
||||
<return type="bool" />
|
||||
<argument index="0" name="mode" type="int" enum="XRInterface.PlayAreaMode" />
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="_trigger_haptic_pulse" qualifiers="virtual">
|
||||
<return type="void" />
|
||||
<argument index="0" name="action_name" type="String" />
|
||||
|
|
|
@ -37,5 +37,6 @@
|
|||
<member name="oversample" type="float" setter="set_oversample" getter="get_oversample" default="1.5">
|
||||
The oversample setting. Because of the lens distortion we have to render our buffers at a higher resolution then the screen can natively handle. A value between 1.5 and 2.0 often provides good results but at the cost of performance.
|
||||
</member>
|
||||
<member name="xr_play_area_mode" type="int" setter="set_play_area_mode" getter="get_play_area_mode" override="true" enum="XRInterface.PlayAreaMode" default="1" />
|
||||
</members>
|
||||
</class>
|
||||
|
|
|
@ -370,6 +370,19 @@ void MobileVRInterface::uninitialize() {
|
|||
};
|
||||
};
|
||||
|
||||
bool MobileVRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
|
||||
// This interface has no positional tracking so fix this to 3DOF
|
||||
return p_mode == XR_PLAY_AREA_3DOF;
|
||||
}
|
||||
|
||||
XRInterface::PlayAreaMode MobileVRInterface::get_play_area_mode() const {
|
||||
return XR_PLAY_AREA_3DOF;
|
||||
}
|
||||
|
||||
bool MobileVRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
|
||||
return p_mode == XR_PLAY_AREA_3DOF;
|
||||
}
|
||||
|
||||
Size2 MobileVRInterface::get_render_target_size() {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
|
|
|
@ -143,6 +143,10 @@ public:
|
|||
virtual bool initialize() override;
|
||||
virtual void uninitialize() override;
|
||||
|
||||
virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
|
||||
virtual XRInterface::PlayAreaMode get_play_area_mode() const override;
|
||||
virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
|
||||
|
||||
virtual Size2 get_render_target_size() override;
|
||||
virtual uint32_t get_view_count() override;
|
||||
virtual Transform3D get_camera_transform() override;
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
// #include "servers/rendering/renderer_compositor.h"
|
||||
|
||||
void XRInterface::_bind_methods() {
|
||||
ADD_SIGNAL(MethodInfo("play_area_changed", PropertyInfo(Variant::INT, "mode")));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_name"), &XRInterface::get_name);
|
||||
ClassDB::bind_method(D_METHOD("get_capabilities"), &XRInterface::get_capabilities);
|
||||
|
||||
|
@ -52,9 +54,16 @@ void XRInterface::_bind_methods() {
|
|||
ADD_GROUP("Interface", "interface_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_primary", "is_primary");
|
||||
|
||||
// we don't have any properties specific to VR yet....
|
||||
// methods and properties specific to VR...
|
||||
ClassDB::bind_method(D_METHOD("supports_play_area_mode", "mode"), &XRInterface::supports_play_area_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_play_area_mode"), &XRInterface::get_play_area_mode);
|
||||
ClassDB::bind_method(D_METHOD("set_play_area_mode", "mode"), &XRInterface::set_play_area_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_play_area"), &XRInterface::get_play_area);
|
||||
|
||||
// but we do have properties specific to AR....
|
||||
ADD_GROUP("XR", "xr_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "xr_play_area_mode", PROPERTY_HINT_ENUM, "Unknown,3DOF,Sitting,Roomscale,Stage"), "set_play_area_mode", "get_play_area_mode");
|
||||
|
||||
// methods and properties specific to AR....
|
||||
ClassDB::bind_method(D_METHOD("get_anchor_detection_is_enabled"), &XRInterface::get_anchor_detection_is_enabled);
|
||||
ClassDB::bind_method(D_METHOD("set_anchor_detection_is_enabled", "enable"), &XRInterface::set_anchor_detection_is_enabled);
|
||||
ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &XRInterface::get_camera_feed_id);
|
||||
|
@ -75,7 +84,13 @@ void XRInterface::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(XR_INSUFFICIENT_FEATURES);
|
||||
BIND_ENUM_CONSTANT(XR_UNKNOWN_TRACKING);
|
||||
BIND_ENUM_CONSTANT(XR_NOT_TRACKING);
|
||||
}
|
||||
|
||||
BIND_ENUM_CONSTANT(XR_PLAY_AREA_UNKNOWN);
|
||||
BIND_ENUM_CONSTANT(XR_PLAY_AREA_3DOF);
|
||||
BIND_ENUM_CONSTANT(XR_PLAY_AREA_SITTING);
|
||||
BIND_ENUM_CONSTANT(XR_PLAY_AREA_ROOMSCALE);
|
||||
BIND_ENUM_CONSTANT(XR_PLAY_AREA_STAGE);
|
||||
};
|
||||
|
||||
bool XRInterface::is_primary() {
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
|
@ -101,6 +116,29 @@ XRInterface::XRInterface() {}
|
|||
|
||||
XRInterface::~XRInterface() {}
|
||||
|
||||
// query if this interface supports this play area mode
|
||||
bool XRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
|
||||
return p_mode == XR_PLAY_AREA_UNKNOWN;
|
||||
}
|
||||
|
||||
// get the current play area mode
|
||||
XRInterface::PlayAreaMode XRInterface::get_play_area_mode() const {
|
||||
return XR_PLAY_AREA_UNKNOWN;
|
||||
}
|
||||
|
||||
// change the play area mode, note that this should return false if the mode is not available
|
||||
bool XRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
|
||||
return p_mode == XR_PLAY_AREA_UNKNOWN;
|
||||
}
|
||||
|
||||
// if available, returns an array of vectors denoting the play area the player can move around in
|
||||
PackedVector3Array XRInterface::get_play_area() const {
|
||||
// Return an empty array by default.
|
||||
// Note implementation is responsible for applying our reference frame and world scale to the raw data.
|
||||
// `play_area_changed` should be emitted if play area data is available and either the reference frame or world scale changes.
|
||||
return PackedVector3Array();
|
||||
};
|
||||
|
||||
/** these will only be implemented on AR interfaces, so we want dummies for VR **/
|
||||
bool XRInterface::get_anchor_detection_is_enabled() const {
|
||||
return false;
|
||||
|
|
|
@ -72,7 +72,14 @@ public:
|
|||
XR_NOT_TRACKING
|
||||
};
|
||||
|
||||
private:
|
||||
enum PlayAreaMode { /* defines the mode used by the XR interface for tracking */
|
||||
XR_PLAY_AREA_UNKNOWN, /* Area mode not set or not available */
|
||||
XR_PLAY_AREA_3DOF, /* Only support orientation tracking, no positional tracking, area will center around player */
|
||||
XR_PLAY_AREA_SITTING, /* Player is in seated position, limited positional tracking, fixed guardian around player */
|
||||
XR_PLAY_AREA_ROOMSCALE, /* Player is free to move around, full positional tracking */
|
||||
XR_PLAY_AREA_STAGE, /* Same as roomscale but origin point is fixed to the center of the physical space, XRServer.center_on_hmd disabled */
|
||||
};
|
||||
|
||||
protected:
|
||||
_THREAD_SAFE_CLASS_
|
||||
|
||||
|
@ -98,7 +105,10 @@ public:
|
|||
virtual void trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0); /* trigger a haptic pulse */
|
||||
|
||||
/** specific to VR **/
|
||||
// nothing yet
|
||||
virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode); /* query if this interface supports this play area mode */
|
||||
virtual XRInterface::PlayAreaMode get_play_area_mode() const; /* get the current play area mode */
|
||||
virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode); /* change the play area mode, note that this should return false if the mode is not available */
|
||||
virtual PackedVector3Array get_play_area() const; /* if available, returns an array of vectors denoting the play area the player can move around in */
|
||||
|
||||
/** specific to AR **/
|
||||
virtual bool get_anchor_detection_is_enabled() const;
|
||||
|
@ -126,5 +136,6 @@ public:
|
|||
|
||||
VARIANT_ENUM_CAST(XRInterface::Capabilities);
|
||||
VARIANT_ENUM_CAST(XRInterface::TrackingStatus);
|
||||
VARIANT_ENUM_CAST(XRInterface::PlayAreaMode);
|
||||
|
||||
#endif // !XR_INTERFACE_H
|
||||
|
|
|
@ -41,6 +41,13 @@ void XRInterfaceExtension::_bind_methods() {
|
|||
GDVIRTUAL_BIND(_initialize);
|
||||
GDVIRTUAL_BIND(_uninitialize);
|
||||
|
||||
GDVIRTUAL_BIND(_get_tracking_status);
|
||||
|
||||
GDVIRTUAL_BIND(_supports_play_area_mode, "mode");
|
||||
GDVIRTUAL_BIND(_get_play_area_mode);
|
||||
GDVIRTUAL_BIND(_set_play_area_mode, "mode");
|
||||
GDVIRTUAL_BIND(_get_play_area);
|
||||
|
||||
GDVIRTUAL_BIND(_get_render_target_size);
|
||||
GDVIRTUAL_BIND(_get_view_count);
|
||||
GDVIRTUAL_BIND(_get_camera_transform);
|
||||
|
@ -146,6 +153,44 @@ void XRInterfaceExtension::trigger_haptic_pulse(const String &p_action_name, con
|
|||
GDVIRTUAL_CALL(_trigger_haptic_pulse, p_action_name, p_tracker_name, p_frequency, p_amplitude, p_duration_sec, p_delay_sec);
|
||||
}
|
||||
|
||||
bool XRInterfaceExtension::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
|
||||
bool is_supported;
|
||||
|
||||
if (GDVIRTUAL_CALL(_supports_play_area_mode, p_mode, is_supported)) {
|
||||
return is_supported;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
XRInterface::PlayAreaMode XRInterfaceExtension::get_play_area_mode() const {
|
||||
uint32_t mode;
|
||||
|
||||
if (GDVIRTUAL_CALL(_get_play_area_mode, mode)) {
|
||||
return XRInterface::PlayAreaMode(mode);
|
||||
}
|
||||
|
||||
return XRInterface::XR_PLAY_AREA_UNKNOWN;
|
||||
}
|
||||
|
||||
bool XRInterfaceExtension::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
|
||||
bool success;
|
||||
|
||||
if (GDVIRTUAL_CALL(_set_play_area_mode, p_mode, success)) {
|
||||
return success;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
PackedVector3Array XRInterfaceExtension::get_play_area() const {
|
||||
PackedVector3Array arr;
|
||||
|
||||
GDVIRTUAL_CALL(_get_play_area, arr);
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/** these will only be implemented on AR interfaces, so we want dummies for VR **/
|
||||
bool XRInterfaceExtension::get_anchor_detection_is_enabled() const {
|
||||
bool enabled;
|
||||
|
|
|
@ -75,7 +75,15 @@ public:
|
|||
GDVIRTUAL6(_trigger_haptic_pulse, const String &, const StringName &, double, double, double, double);
|
||||
|
||||
/** specific to VR **/
|
||||
// nothing yet
|
||||
virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override; /* query if this interface supports this play area mode */
|
||||
virtual XRInterface::PlayAreaMode get_play_area_mode() const override; /* get the current play area mode */
|
||||
virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override; /* change the play area mode, note that this should return false if the mode is not available */
|
||||
virtual PackedVector3Array get_play_area() const override; /* if available, returns an array of vectors denoting the play area the player can move around in */
|
||||
|
||||
GDVIRTUAL1RC(bool, _supports_play_area_mode, XRInterface::PlayAreaMode);
|
||||
GDVIRTUAL0RC(uint32_t, _get_play_area_mode);
|
||||
GDVIRTUAL1RC(bool, _set_play_area_mode, uint32_t);
|
||||
GDVIRTUAL0RC(PackedVector3Array, _get_play_area);
|
||||
|
||||
/** specific to AR **/
|
||||
virtual bool get_anchor_detection_is_enabled() const override;
|
||||
|
|
|
@ -116,35 +116,43 @@ Transform3D XRServer::get_reference_frame() const {
|
|||
};
|
||||
|
||||
void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) {
|
||||
if (primary_interface != nullptr) {
|
||||
// clear our current reference frame or we'll end up double adjusting it
|
||||
if (primary_interface == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (primary_interface->get_play_area_mode() == XRInterface::XR_PLAY_AREA_STAGE) {
|
||||
// center_on_hmd is not available in this mode
|
||||
reference_frame = Transform3D();
|
||||
return;
|
||||
}
|
||||
|
||||
// requesting our EYE_MONO transform should return our current HMD position
|
||||
Transform3D new_reference_frame = primary_interface->get_camera_transform();
|
||||
// clear our current reference frame or we'll end up double adjusting it
|
||||
reference_frame = Transform3D();
|
||||
|
||||
// remove our tilt
|
||||
if (p_rotation_mode == 1) {
|
||||
// take the Y out of our Z
|
||||
new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized());
|
||||
// requesting our EYE_MONO transform should return our current HMD position
|
||||
Transform3D new_reference_frame = primary_interface->get_camera_transform();
|
||||
|
||||
// Y is straight up
|
||||
new_reference_frame.basis.set_axis(1, Vector3(0.0, 1.0, 0.0));
|
||||
// remove our tilt
|
||||
if (p_rotation_mode == 1) {
|
||||
// take the Y out of our Z
|
||||
new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized());
|
||||
|
||||
// and X is our cross reference
|
||||
new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized());
|
||||
} else if (p_rotation_mode == 2) {
|
||||
// remove our rotation, we're only interesting in centering on position
|
||||
new_reference_frame.basis = Basis();
|
||||
};
|
||||
// Y is straight up
|
||||
new_reference_frame.basis.set_axis(1, Vector3(0.0, 1.0, 0.0));
|
||||
|
||||
// don't negate our height
|
||||
if (p_keep_height) {
|
||||
new_reference_frame.origin.y = 0.0;
|
||||
};
|
||||
|
||||
reference_frame = new_reference_frame.inverse();
|
||||
// and X is our cross reference
|
||||
new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized());
|
||||
} else if (p_rotation_mode == 2) {
|
||||
// remove our rotation, we're only interesting in centering on position
|
||||
new_reference_frame.basis = Basis();
|
||||
};
|
||||
|
||||
// don't negate our height
|
||||
if (p_keep_height) {
|
||||
new_reference_frame.origin.y = 0.0;
|
||||
};
|
||||
|
||||
reference_frame = new_reference_frame.inverse();
|
||||
};
|
||||
|
||||
Transform3D XRServer::get_hmd_transform() {
|
||||
|
|
Loading…
Reference in a new issue