facebookarchive / react-360

Create amazing 360 and VR content using React
https://facebook.github.io/react-360
Other
8.73k stars 1.23k forks source link

Feature Request: Allow configuration of Controls #44

Closed philsawicki closed 7 years ago

philsawicki commented 7 years ago

Description

When attempting to customize the vrControls and nonVRControls of a Project, I struggled to find a way to configure them at initialization.

This originates from a need to support Touch inputs on both the DeviceOrientationControls and the MousePanControls, in order to allow User to refocus the Scene in case of Device Drift when designing for sit-down experiences while also supporting Touch Screen laptops and tablets.

I was able to override the VRInstance's instances of vrControls and nonVRControls with custom ones, but the internal Device fingerprinting to select which Controls to use (i.e. DeviceOrientationControls.isSupported()) is already executed (see Reproduction below).

Expected behavior

The init() function of client.js allows Developers to specify which vrControls and nonVRControls instances to use in the VRInstance() Constructor, with a way of selecting which one to use (see Solution below).

Actual behavior

The VRInstance() Constructor does not support passing custom Controls, and they must be overridden from the vr instance returned.

Reproduction

Simple vr/client.js used to workaround creation of custom Controls:

import { VRInstance } from 'react-vr-web';

import CustomMousePanControls from './CustomMousePanControls';
import CustomDeviceOrientationControls from './CustomDeviceOrientationControls';
import { BROWSER_SUPPORTS_DEVICE_ORIENTATION, IS_MOBILE_DEVICE } from './vr-utilities';

/**
 * Setup the Application's Controls.
 *
 * @param {VRInstance} vr A reference to the VRInstance.
 * @param {?Object} nonVRControls Constructor for Controls to use for non-VR setups.
 * @param {?Object} vrControls Constructor for Controls to use for VR setups.
 */
function setupControls(vr, nonVRControls, vrControls) {
    // Non-VR Controls:
    if (vr.player.controls.nonVRControls && typeof nonVRControls === 'function') {
        if (typeof vr.player.controls.nonVRControls.disconnect === 'function') {
            vr.player.controls.nonVRControls.disconnect();
        }
        // Assume "connect()" is called from the Constructor:
        vr.player.controls.nonVRControls = new nonVRControls(vr.player.camera);
    }

    // VR Controls:
    if (vr.player.controls.vrControls && typeof vrControls === 'function') {
        if (typeof vr.player.controls.vrControls.disconnect === 'function') {
            vr.player.controls.vrControls.disconnect();
        }
        // Assume "connect()" is called from the Constructor:
        vr.player.controls.vrControls = new vrControls(vr.player.camera);
    }
}

function init(bundle, parent, options = {}) {
    // Use "mobile" Controls?
    const useMobileControls = BROWSER_SUPPORTS_DEVICE_ORIENTATION && IS_MOBILE_DEVICE;

    // Only set "cursorVisibility" if it was not defined earlier:
    if (typeof options.cursorVisibility !== 'string') {
        options.cursorVisibility = useMobileControls ? 'visible' : 'hidden';
    }

    const vr = new VRInstance(bundle, 'ReactVRTest', parent, {
        // Add custom options here:
        ...options
    });

    // Select the Controls to use for the Application:
    setupControls(
        vr,
        useMobileControls ? CustomDeviceOrientationControls : CustomMousePanControls,
        null);

    vr.render = function(timestamp) {
        // Any custom behavior you want to perform on each frame goes here
    };

    // Begin the animation loop:
    vr.start();
    return vr;
}

window.ReactVR = { init };

Solution

The VRInstance() Constructor could support additional (optional) parameters to specific which Controls to use and when:

const vr = new VRInstance(bundle, 'ProjectName', parent, {
    controls: {
        vrControls: CustomVRControls,
        nonVRControls: CustomNonVRControls,
        // Callback to use in order to select which Controls to use:
        useVRControls: () => false // Default value.
    },
    ...options
});

Thanks for your time!

Additional Information

amberroy commented 7 years ago

Thanks for the detailed repro and solution. extending VRInstance to support custom Controls is a great idea, will add to our list.

philsawicki commented 7 years ago

Great! Thanks for your time and consideration @amberroy!

(I'll close this Issue, as its main purpose was to bring this suggestion to your attention.)