Add WebXRInterface.xr_standard_mapping flag to attempt to convert button/axis ids to match other AR/VR interfaces
This commit is contained in:
parent
14856b1dbd
commit
2a6199aa0f
7 changed files with 107 additions and 25 deletions
|
@ -22,6 +22,9 @@
|
||||||
|
|
||||||
webxr_interface = ARVRServer.find_interface("WebXR")
|
webxr_interface = ARVRServer.find_interface("WebXR")
|
||||||
if webxr_interface:
|
if webxr_interface:
|
||||||
|
# Map to the standard button/axis ids when possible.
|
||||||
|
webxr_interface.xr_standard_mapping = true
|
||||||
|
|
||||||
# WebXR uses a lot of asynchronous callbacks, so we connect to various
|
# WebXR uses a lot of asynchronous callbacks, so we connect to various
|
||||||
# signals in order to receive them.
|
# signals in order to receive them.
|
||||||
webxr_interface.connect("session_supported", self, "_webxr_session_supported")
|
webxr_interface.connect("session_supported", self, "_webxr_session_supported")
|
||||||
|
@ -164,6 +167,10 @@
|
||||||
Indicates if the WebXR session's imagery is visible to the user.
|
Indicates if the WebXR session's imagery is visible to the user.
|
||||||
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRVisibilityState]WebXR's XRVisibilityState[/url], including [code]"hidden"[/code], [code]"visible"[/code], and [code]"visible-blurred"[/code].
|
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRVisibilityState]WebXR's XRVisibilityState[/url], including [code]"hidden"[/code], [code]"visible"[/code], and [code]"visible-blurred"[/code].
|
||||||
</member>
|
</member>
|
||||||
|
<member name="xr_standard_mapping" type="bool" setter="set_xr_standard_mapping" getter="get_xr_standard_mapping">
|
||||||
|
If set to true, the button and axes ids will be converted to match the standard ids used by other AR/VR interfaces, when possible.
|
||||||
|
Otherwise, the ids will be passed through unaltered from WebXR.
|
||||||
|
</member>
|
||||||
</members>
|
</members>
|
||||||
<signals>
|
<signals>
|
||||||
<signal name="reference_space_reset">
|
<signal name="reference_space_reset">
|
||||||
|
|
|
@ -80,8 +80,8 @@ extern void godot_webxr_sample_controller_data();
|
||||||
extern int godot_webxr_get_controller_count();
|
extern int godot_webxr_get_controller_count();
|
||||||
extern int godot_webxr_is_controller_connected(int p_controller);
|
extern int godot_webxr_is_controller_connected(int p_controller);
|
||||||
extern float *godot_webxr_get_controller_transform(int p_controller);
|
extern float *godot_webxr_get_controller_transform(int p_controller);
|
||||||
extern int *godot_webxr_get_controller_buttons(int p_controller);
|
extern int *godot_webxr_get_controller_buttons(int p_controller, bool p_xr_standard_mapping);
|
||||||
extern int *godot_webxr_get_controller_axes(int p_controller);
|
extern int *godot_webxr_get_controller_axes(int p_controller, bool p_xr_standard_mapping);
|
||||||
extern int godot_webxr_get_controller_target_ray_mode(int p_controller);
|
extern int godot_webxr_get_controller_target_ray_mode(int p_controller);
|
||||||
|
|
||||||
extern char *godot_webxr_get_visibility_state();
|
extern char *godot_webxr_get_visibility_state();
|
||||||
|
|
|
@ -524,8 +524,8 @@ const GodotWebXR = {
|
||||||
},
|
},
|
||||||
|
|
||||||
godot_webxr_get_controller_buttons__proxy: 'sync',
|
godot_webxr_get_controller_buttons__proxy: 'sync',
|
||||||
godot_webxr_get_controller_buttons__sig: 'ii',
|
godot_webxr_get_controller_buttons__sig: 'iii',
|
||||||
godot_webxr_get_controller_buttons: function (p_controller) {
|
godot_webxr_get_controller_buttons: function (p_controller, p_xr_standard_mapping) {
|
||||||
if (GodotWebXR.controllers.length === 0) {
|
if (GodotWebXR.controllers.length === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -535,19 +535,55 @@ const GodotWebXR = {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const button_count = controller.gamepad.buttons.length;
|
let buttons = controller.gamepad.buttons;
|
||||||
|
if (controller.gamepad.mapping === 'xr-standard' && p_xr_standard_mapping) {
|
||||||
|
buttons = [
|
||||||
|
// 0 = unused,
|
||||||
|
0,
|
||||||
|
// 1 = B/Y
|
||||||
|
buttons[5],
|
||||||
|
// 2 = Grip
|
||||||
|
buttons[1],
|
||||||
|
// 3
|
||||||
|
buttons[3],
|
||||||
|
// 4
|
||||||
|
buttons[6],
|
||||||
|
// 5
|
||||||
|
buttons[7],
|
||||||
|
// 6
|
||||||
|
buttons[8],
|
||||||
|
// 7 = A/X
|
||||||
|
buttons[4],
|
||||||
|
// 8
|
||||||
|
buttons[9],
|
||||||
|
// 9
|
||||||
|
buttons[10],
|
||||||
|
// 10
|
||||||
|
buttons[11],
|
||||||
|
// 11
|
||||||
|
buttons[12],
|
||||||
|
// 12
|
||||||
|
buttons[13],
|
||||||
|
// 13
|
||||||
|
buttons[14],
|
||||||
|
// 14 = Pad
|
||||||
|
buttons[2],
|
||||||
|
// 15 = Trigger
|
||||||
|
buttons[0],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
const buf = GodotRuntime.malloc((button_count + 1) * 4);
|
const buf = GodotRuntime.malloc((buttons.length + 1) * 4);
|
||||||
GodotRuntime.setHeapValue(buf, button_count, 'i32');
|
GodotRuntime.setHeapValue(buf, buttons.length, 'i32');
|
||||||
for (let i = 0; i < button_count; i++) {
|
for (let i = 0; i < buttons.length; i++) {
|
||||||
GodotRuntime.setHeapValue(buf + 4 + (i * 4), controller.gamepad.buttons[i].value, 'float');
|
GodotRuntime.setHeapValue(buf + 4 + (i * 4), (buttons[i] ? buttons[i].value : 0.0), 'float');
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
},
|
},
|
||||||
|
|
||||||
godot_webxr_get_controller_axes__proxy: 'sync',
|
godot_webxr_get_controller_axes__proxy: 'sync',
|
||||||
godot_webxr_get_controller_axes__sig: 'ii',
|
godot_webxr_get_controller_axes__sig: 'iii',
|
||||||
godot_webxr_get_controller_axes: function (p_controller) {
|
godot_webxr_get_controller_axes: function (p_controller, p_xr_standard_mapping) {
|
||||||
if (GodotWebXR.controllers.length === 0) {
|
if (GodotWebXR.controllers.length === 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -557,18 +593,41 @@ const GodotWebXR = {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const axes_count = controller.gamepad.axes.length;
|
let axes = controller.gamepad.axes;
|
||||||
|
if (controller.gamepad.mapping === 'xr-standard') {
|
||||||
const buf = GodotRuntime.malloc((axes_count + 1) * 4);
|
if (p_xr_standard_mapping) {
|
||||||
GodotRuntime.setHeapValue(buf, axes_count, 'i32');
|
const trigger_axis = controller.gamepad.buttons[0].value;
|
||||||
for (let i = 0; i < axes_count; i++) {
|
const grip_axis = controller.gamepad.buttons[1].value;
|
||||||
let value = controller.gamepad.axes[i];
|
axes = [
|
||||||
if (i === 1 || i === 3) {
|
// 0 = Thumbstick X
|
||||||
|
axes[2],
|
||||||
|
// 1 = Thumbstick Y
|
||||||
|
axes[3] * -1.0,
|
||||||
|
// 2 = Trigger
|
||||||
|
trigger_axis,
|
||||||
|
// 3 = Grip (to match mistake in Oculus mobile plugin).
|
||||||
|
grip_axis,
|
||||||
|
// 4 = Grip
|
||||||
|
grip_axis,
|
||||||
|
// 5 = unused
|
||||||
|
0,
|
||||||
|
// 6 = Trackpad X
|
||||||
|
axes[0],
|
||||||
|
// 7 = Trackpad Y
|
||||||
|
axes[1] * -1.0,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
// Invert the Y-axis on thumbsticks and trackpads, in order to
|
// Invert the Y-axis on thumbsticks and trackpads, in order to
|
||||||
// match OpenXR and other XR platform SDKs.
|
// match OpenXR and other XR platform SDKs.
|
||||||
value *= -1.0;
|
axes[1] *= -1.0;
|
||||||
|
axes[3] *= -1.0;
|
||||||
}
|
}
|
||||||
GodotRuntime.setHeapValue(buf + 4 + (i * 4), value, 'float');
|
}
|
||||||
|
|
||||||
|
const buf = GodotRuntime.malloc((axes.length + 1) * 4);
|
||||||
|
GodotRuntime.setHeapValue(buf, axes.length, 'i32');
|
||||||
|
for (let i = 0; i < axes.length; i++) {
|
||||||
|
GodotRuntime.setHeapValue(buf + 4 + (i * 4), axes[i], 'float');
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,6 +46,8 @@ void WebXRInterface::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_controller_target_ray_mode", "controller_id"), &WebXRInterface::get_controller_target_ray_mode);
|
ClassDB::bind_method(D_METHOD("get_controller_target_ray_mode", "controller_id"), &WebXRInterface::get_controller_target_ray_mode);
|
||||||
ClassDB::bind_method(D_METHOD("get_visibility_state"), &WebXRInterface::get_visibility_state);
|
ClassDB::bind_method(D_METHOD("get_visibility_state"), &WebXRInterface::get_visibility_state);
|
||||||
ClassDB::bind_method(D_METHOD("get_bounds_geometry"), &WebXRInterface::get_bounds_geometry);
|
ClassDB::bind_method(D_METHOD("get_bounds_geometry"), &WebXRInterface::get_bounds_geometry);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_xr_standard_mapping"), &WebXRInterface::set_xr_standard_mapping);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_xr_standard_mapping"), &WebXRInterface::get_xr_standard_mapping);
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "session_mode", PROPERTY_HINT_NONE), "set_session_mode", "get_session_mode");
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "session_mode", PROPERTY_HINT_NONE), "set_session_mode", "get_session_mode");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "required_features", PROPERTY_HINT_NONE), "set_required_features", "get_required_features");
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "required_features", PROPERTY_HINT_NONE), "set_required_features", "get_required_features");
|
||||||
|
@ -54,6 +56,7 @@ void WebXRInterface::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "reference_space_type", PROPERTY_HINT_NONE), "", "get_reference_space_type");
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "reference_space_type", PROPERTY_HINT_NONE), "", "get_reference_space_type");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "visibility_state", PROPERTY_HINT_NONE), "", "get_visibility_state");
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "visibility_state", PROPERTY_HINT_NONE), "", "get_visibility_state");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "bounds_geometry", PROPERTY_HINT_NONE), "", "get_bounds_geometry");
|
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "bounds_geometry", PROPERTY_HINT_NONE), "", "get_bounds_geometry");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "xr_standard_mapping", PROPERTY_HINT_NONE), "set_xr_standard_mapping", "get_xr_standard_mapping");
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("session_supported", PropertyInfo(Variant::STRING, "session_mode"), PropertyInfo(Variant::BOOL, "supported")));
|
ADD_SIGNAL(MethodInfo("session_supported", PropertyInfo(Variant::STRING, "session_mode"), PropertyInfo(Variant::BOOL, "supported")));
|
||||||
ADD_SIGNAL(MethodInfo("session_started"));
|
ADD_SIGNAL(MethodInfo("session_started"));
|
||||||
|
|
|
@ -68,6 +68,8 @@ public:
|
||||||
virtual TargetRayMode get_controller_target_ray_mode(int p_controller_id) const = 0;
|
virtual TargetRayMode get_controller_target_ray_mode(int p_controller_id) const = 0;
|
||||||
virtual String get_visibility_state() const = 0;
|
virtual String get_visibility_state() const = 0;
|
||||||
virtual PoolVector3Array get_bounds_geometry() const = 0;
|
virtual PoolVector3Array get_bounds_geometry() const = 0;
|
||||||
|
virtual void set_xr_standard_mapping(bool p_xr_standard_mapping) = 0;
|
||||||
|
virtual bool get_xr_standard_mapping() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(WebXRInterface::TargetRayMode);
|
VARIANT_ENUM_CAST(WebXRInterface::TargetRayMode);
|
||||||
|
|
|
@ -204,6 +204,14 @@ PoolVector3Array WebXRInterfaceJS::get_bounds_geometry() const {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebXRInterfaceJS::set_xr_standard_mapping(bool p_xr_standard_mapping) {
|
||||||
|
xr_standard_mapping = p_xr_standard_mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebXRInterfaceJS::get_xr_standard_mapping() const {
|
||||||
|
return xr_standard_mapping;
|
||||||
|
}
|
||||||
|
|
||||||
StringName WebXRInterfaceJS::get_name() const {
|
StringName WebXRInterfaceJS::get_name() const {
|
||||||
return "WebXR";
|
return "WebXR";
|
||||||
};
|
};
|
||||||
|
@ -417,7 +425,7 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
|
||||||
free(tracker_matrix);
|
free(tracker_matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
int *buttons = godot_webxr_get_controller_buttons(p_controller_id);
|
int *buttons = godot_webxr_get_controller_buttons(p_controller_id, xr_standard_mapping);
|
||||||
if (buttons) {
|
if (buttons) {
|
||||||
for (int i = 0; i < buttons[0]; i++) {
|
for (int i = 0; i < buttons[0]; i++) {
|
||||||
input->joy_button(joy_id, i, *((float *)buttons + (i + 1)));
|
input->joy_button(joy_id, i, *((float *)buttons + (i + 1)));
|
||||||
|
@ -425,7 +433,7 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
|
||||||
free(buttons);
|
free(buttons);
|
||||||
}
|
}
|
||||||
|
|
||||||
int *axes = godot_webxr_get_controller_axes(p_controller_id);
|
int *axes = godot_webxr_get_controller_axes(p_controller_id, xr_standard_mapping);
|
||||||
if (axes) {
|
if (axes) {
|
||||||
WebXRInterface::TargetRayMode target_ray_mode = (WebXRInterface::TargetRayMode)godot_webxr_get_controller_target_ray_mode(p_controller_id);
|
WebXRInterface::TargetRayMode target_ray_mode = (WebXRInterface::TargetRayMode)godot_webxr_get_controller_target_ray_mode(p_controller_id);
|
||||||
if (target_ray_mode == WebXRInterface::TARGET_RAY_MODE_SCREEN) {
|
if (target_ray_mode == WebXRInterface::TARGET_RAY_MODE_SCREEN) {
|
||||||
|
@ -481,7 +489,7 @@ void WebXRInterfaceJS::_on_input_event(int p_event_type, int p_input_source) {
|
||||||
touching[touch_index] = (p_event_type == WEBXR_INPUT_EVENT_SELECTSTART);
|
touching[touch_index] = (p_event_type == WEBXR_INPUT_EVENT_SELECTSTART);
|
||||||
}
|
}
|
||||||
|
|
||||||
int *axes = godot_webxr_get_controller_axes(p_input_source);
|
int *axes = godot_webxr_get_controller_axes(p_input_source, false);
|
||||||
if (axes) {
|
if (axes) {
|
||||||
Vector2 joy_vector = _get_joy_vector_from_axes(axes);
|
Vector2 joy_vector = _get_joy_vector_from_axes(axes);
|
||||||
Vector2 position = _get_screen_position_from_joy_vector(joy_vector);
|
Vector2 position = _get_screen_position_from_joy_vector(joy_vector);
|
||||||
|
@ -554,8 +562,7 @@ Vector2 WebXRInterfaceJS::_get_joy_vector_from_axes(int *p_axes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 WebXRInterfaceJS::_get_screen_position_from_joy_vector(const Vector2 &p_joy_vector) {
|
Vector2 WebXRInterfaceJS::_get_screen_position_from_joy_vector(const Vector2 &p_joy_vector) {
|
||||||
// Invert the y-axis.
|
Vector2 position_percentage((p_joy_vector.x + 1.0f) / 2.0f, ((p_joy_vector.y) + 1.0f) / 2.0f);
|
||||||
Vector2 position_percentage((p_joy_vector.x + 1.0f) / 2.0f, ((-p_joy_vector.y) + 1.0f) / 2.0f);
|
|
||||||
Vector2 position = get_render_targetsize() * position_percentage;
|
Vector2 position = get_render_targetsize() * position_percentage;
|
||||||
|
|
||||||
return position;
|
return position;
|
||||||
|
@ -567,6 +574,7 @@ void WebXRInterfaceJS::notification(int p_what) {
|
||||||
|
|
||||||
WebXRInterfaceJS::WebXRInterfaceJS() {
|
WebXRInterfaceJS::WebXRInterfaceJS() {
|
||||||
initialized = false;
|
initialized = false;
|
||||||
|
xr_standard_mapping = false;
|
||||||
session_mode = "inline";
|
session_mode = "inline";
|
||||||
requested_reference_space_types = "local";
|
requested_reference_space_types = "local";
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,6 +46,7 @@ class WebXRInterfaceJS : public WebXRInterface {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
bool xr_standard_mapping;
|
||||||
|
|
||||||
String session_mode;
|
String session_mode;
|
||||||
String required_features;
|
String required_features;
|
||||||
|
@ -80,6 +81,8 @@ public:
|
||||||
virtual TargetRayMode get_controller_target_ray_mode(int p_controller_id) const;
|
virtual TargetRayMode get_controller_target_ray_mode(int p_controller_id) const;
|
||||||
virtual String get_visibility_state() const;
|
virtual String get_visibility_state() const;
|
||||||
virtual PoolVector3Array get_bounds_geometry() const;
|
virtual PoolVector3Array get_bounds_geometry() const;
|
||||||
|
virtual void set_xr_standard_mapping(bool p_xr_standard_mapping);
|
||||||
|
virtual bool get_xr_standard_mapping() const;
|
||||||
|
|
||||||
virtual StringName get_name() const;
|
virtual StringName get_name() const;
|
||||||
virtual int get_capabilities() const;
|
virtual int get_capabilities() const;
|
||||||
|
|
Loading…
Reference in a new issue