w3c / gamepad

Gamepad
https://w3c.github.io/gamepad/
Other
142 stars 48 forks source link

GamepadHapticActuator pulse should support frequency parameter #148

Open davehill00 opened 3 years ago

davehill00 commented 3 years ago

Many haptic actuators support both pulsing at different frequencies, which provides a wider range of expressiveness in haptic feedback. The pulse function could easily be extended to support a 0..1 frequency value as well (which the UA could easily ignore if the hardware doesn't support different frequencies).

marcoscaceres commented 3 years ago

Thanks @davehill00! We will revise your proposal later this week.

davehill00 commented 3 years ago

Thanks, @marcoscaceres! We're interested in adding support for this to Oculus Browser.

nondebug commented 3 years ago

The GamepadHapticActuator definition in the Gamepad Extensions spec is out of date and I don't think it was ever fully implemented in any browser. Firefox has IDL for it but as far as I can tell none of the platform backends ever create any actuators.

Chromium implements the haptics API described in the pull request here. It's designed for DualShock-style haptics as opposed to the pulse effect in the original GamepadHapticActuator spec. DualShock controllers have two eccentric rotating mass (ERM) actuators with differing masses that can be run at different speeds to create rumble effects. The haptics element responsible for vibrating the whole controller is exposed as Gamepad.vibrationActuator. Example usage:

let gamepads = navigator.hid.getGamepads();
if (gamepads[0] && gamepads[0].vibrationActuator) {
  gamepads[0].vibrationActuator.playEffect(
      'dual-rumble',  // Effect type
      {duration:1000,  // Vibration duration, in milliseconds
       startDelay:0,  // Delay before starting the effect, in milliseconds
       strongMagnitude:0.5,  // Vibration intensity of the "strong" (low frequency) rumble motor
       weakMagnitude:1.0});  // Vibration intensity of the "weak" (high frequency) rumble motor
}

Currently the spec only defines one type of effect. I think the best user experience occurs when applications can use a single effect type and browsers do their best to support that effect type across all gamepads, even if the gamepad does not have the correct hardware to support that type of effect. For instance, Chrome supports sending dual-rumble effects to a Switch Joy-Con even though the Joy-Con has a linear resonant actuator (LRA) instead of the dual-ERM configuration. This approach might also be appropriate for Oculus VR controllers.

To allow apps to specify a frequency for the effect, we can define new effect types that are better suited for the vibration actuators found in VR controllers. In the Oculus SDK documentation there are two haptics interfaces: OVRInput Haptics which takes (frequency, amplitude, controllerMask) parameters and OVRHaptics which is deprecated. To support the OVRInput Haptics interface perhaps we can add something like:

actuator.playEffect(
    'frequency-pulse',  // Play a pulse effect at a specific frequency
    {duration:1000,  // Vibration duration, in milliseconds
     startDelay:0,  // Delay before starting the effect, in milliseconds
     frequency:60,  // Vibration frequency, in Hz
     magnitude:1.0});  // Vibration intensity (0 = no vibration, 1 = max vibration)

Gamepad.vibrationActuator is intended for effects that vibrate the whole controller, but VR controllers typically have one device per hand, each with its own vibration actuator. I think the best approach here is to expose separate GamepadHapticActuator objects to represent the actuators in the left- and right-hand controllers:

gamepad.leftVibrationActuator.playEffect('frequency-pulse', /*params*/);  // Play effect on left-hand actuator
gamepad.rightVibrationActuator.playEffect('frequency-pulse', /*params*/);  // Play effect on right-hand actuator
gamepad.vibrationActuator.playEffect('frequency-pulse', /*params*/);  // Play effect on both hands
cabanier commented 3 years ago

Gamepad.vibrationActuator is intended for effects that vibrate the whole controller, but VR controllers typically have one device per hand, each with its own vibration actuator. I think the best approach here is to expose separate GamepadHapticActuator objects to represent the actuators in the left- and right-hand controllers:

gamepad.leftVibrationActuator.playEffect('frequency-pulse', /*params*/);  // Play effect on left-hand actuator
gamepad.rightVibrationActuator.playEffect('frequency-pulse', /*params*/);  // Play effect on right-hand actuator
gamepad.vibrationActuator.playEffect('frequency-pulse', /*params*/);  // Play effect on both hands

WebXR surfaces 2 gamepads. I think that means that we don't need separate actuators. Otherwise, the proposal looks reasonable. How do we go about getting it in the specification?

marcoscaceres commented 3 years ago

@cabanier, we'd basically need a pull request (one of the editors can draft it or anyone here might volunteer to do it), tests, and implementation commitment from two implementers.

cabanier commented 2 years ago

@cabanier, we'd basically need a pull request (one of the editors can draft it or anyone here might volunteer to do it), tests, and implementation commitment from two implementers.

One problem is that I'm unaware if there's anyone but Oculus that has control over the frequency of the haptic motor...

cabanier commented 2 years ago

@marcoscaceres @nondebug Quest Controller Pro was released last week with support for 3 haptic actuator. Each can also specify a frequency. I currently implemented these as extra entries in the HapticActuators array but didn't hook up frequency. @nondebug , how far along is the playEffect proposal?