Problem with VR mode (HMD)

Hi,

I have the strangest problem with VR mode.
I have tested the “Web VR Hello World” tutorial example and works.
If I click in the glasses icon, the application enables/disables the VR mode.
I use an HTC Vive and works perfectly.

However, I have been unable so far to make the VR mode work without using the
callback function that the tutorial uses in the “initialize” function of the WebVrUi script.

I have slightly modified the code of the example (WebVrUi script) to enable the VR mode with a key (H Key), since I need to control this mode from the application (not by clicking the mouse) and that was a test to see if I could enable the VR in a different way. But I does not work.

The code works if I click on the glasses icon (it enables and disables the VR mode), but it only works to DISABLE the VR mode if I use the key. It does not work to ENABLE it ¿?¿?¿?¿

The problem is that, although no errors are shown and the functions appear to have been correctly called, the “onVrPresentChange” callback function is not called if the onEnterVrPressedEvent function is not triggered by a mouse click…

The strange thing is that both methods (mouse and keyboard) end up in the SAME FUNCTION!!!

This is my code:

var WebVrUi = pc.createScript('webVrUi');

WebVrUi.attributes.add("camera", {type: "entity", title: "Camera"});
WebVrUi.attributes.add("enterVrWhite", {type: "asset", title: "Enter VR White Asset"});
WebVrUi.attributes.add("enterVrOrange", {type: "asset", title: "Enter VR Orange Asset"});
WebVrUi.attributes.add("infoBoxLifeSpan", {type: "number", default: 3, title: "Info Box Life Span",});

WebVrUi.prototype.initialize = function() 
{    
    if (this.app.vr && this.app.vr.display) 
        this.app.vr.display.on("presentchange", this.onVrPresentChange, this);
    
    this.app.assets.load(this.enterVrWhite);
    this.app.assets.load(this.enterVrOrange);
    
    // HTML UI setup
    var css = '#vr-button {position: absolute;right: 0px;bottom: 0px;background-image: url("'+ this.enterVrWhite.getFileUrl() +'");width: 146px;height: 104px;display: block;'+
        'background-position: 0px 0px;background-size: 146px 104px; cursor: pointer;}' +		
	    '#vr-button:hover {background-image: url("' + this.enterVrOrange.getFileUrl() + '");}' +
        '#info-box {position: absolute;	right: 140px;bottom: 26px;display: block;background-color: rgba(0,0,0, 168);color: rgb(218, 218, 218);padding: 5px 10px 5px 10px;max-width: 220px;}' +
        '#info-box a, #info-box a:hover, #info-box a:visited, #info-box a:active {text-decoration: underline;color: rgb(218, 218, 218);}';
    
    var style = pc.createStyle(css);
    document.head.appendChild(style);
    
    this.vrButtonDiv = document.createElement("div");
    this.vrButtonDiv.id = "vr-button";
    this.vrButtonDiv.innerHTML = "&nbsp"; 
    
    document.body.appendChild(this.vrButtonDiv);
    
    this.infoBoxDiv = document.createElement("div");
    this.infoBoxDiv.id = "info-box";    
    
    this.infoBoxLifeTime = 0;
    this.infoBoxShowing = false;
    
    this.vrEntered = false;
    this.vrButtonDiv.addEventListener('click', function(e) {
            this.onEnterVrPressedEvent(); 
        }.bind(this), 
        false);
    
    // try and enter vr immediately for Carmel browser
    this.onEnterVrPressedEvent();
};

WebVrUi.prototype.onEnterVrPressedEvent = function() 
{
    // If WebVR is available and a VrDisplay is attached
    if (this.app.vr && this.app.vr.display) 
    { 
        if (this.vrEntered) 
        {
            this.camera.camera.exitVr(function (err) {
               if (err)
                 console.log("Error en ExitVR = " + err);
            });
        }
        else 
        {
            this.camera.camera.enterVr(function (err) {
                if (err)
                     console.log("Error en EnterVR = " + err);
            });
        }
    } 
    else 
    {
        if (!this.infoBoxShowing) 
        {
            if (this.app.vr.isSupported) 
                this.infoBoxDiv.innerHTML = "No HMD VR display or headset is detected.";
            else 
                this.infoBoxDiv.innerHTML = "Sorry, your browser does not support WebVR :(. Please go <a href='https://webvr.info/' target='_blank'>here</a> for more information.";

            this.infoBoxLifeTime = this.infoBoxLifeSpan;
            document.body.appendChild(this.infoBoxDiv);
            this.infoBoxShowing = true;
        }
    }
};

WebVrUi.prototype.isMobile = function() 
{
    return /Android/i.test(navigator.userAgent) || /iPhone|iPad|iPod/i.test(navigator.userAgent);
};

// update code called every frame
WebVrUi.prototype.update = function(dt) 
{
    if (this.infoBoxShowing) 
    {
        this.infoBoxLifeTime -= dt;
        
        if (this.infoBoxLifeTime <= 0) 
        {
            document.body.removeChild(this.infoBoxDiv);
            this.infoBoxShowing = false;
        }
    }

    if (this.app.keyboard.wasPressed(pc.KEY_H))
        this.onEnterVrPressedEvent();
};

WebVrUi.prototype.onVrPresentChange = function(display)
{
    if (display.presenting) 
    {
        // Only remove the VR button if we are on mobile
        if (this.isMobile()) 
            document.body.removeChild(this.vrButtonDiv);
        
        this.vrEntered = true;
    } 
    else 
    {
        if (this.isMobile()) 
            document.body.appendChild(this.vrButtonDiv);
        
        this.vrEntered = false;
    }
};

Please help.
I am really starting to think that this is a bug.
It makes no sense at all…

Hmm… It might be that to enter VR, it has to done via a mouse or touch event (similar to video playback via the browser on mobile).

One thing you can try is to try using the keyboard key down event callback rather than the polling method that you have used above.

The difference is then you would be triggering the ‘VR mode’ directly from an input event.

API reference here: https://developer.playcanvas.com/en/api/pc.KeyboardEvent.html

Really???

There is no way to enable VR without using an event?
That means I cannot enable VR programatically from another class, which is what I really want to do.
The keyboard was just an example. I don’t really need to do it with the keyboard, but programatically from another class.

It is very strange that it needs an event (and I think it is not explained in the VR API).
I guess there should be a reason for that but right now, I cannot find any logical one…

It’s a browser based ‘security’ measure. Its stops pages/sites from automatically doing something potentially undesirable without user input. For example, sites can’t go full screen without user input these days to stop full screen takeovers.

Ok.

Then, I guess there is nothing else I can do…

…unless it be possible to emulate a mouse input from one of my classes? Is it??

What’s the intention with using another class to enter VR programatically?

There’s always a physical setup stage where the user has to put on the VR headset so having an user input to start VR seems realistic?

Well,

my Playcanvas application is just a part of another application, which is responsible of controlling the different modes (including the VR mode), so I need a way to create a Playcanvas function that enables VR and can be called from the main application, whichever way this function is called/triggered (keyboard, mouse, automatically, etc.).

That’s the reason.

As long as the call to enter VR derives from an user input event, that might work even across ‘applications’ if that makes sense?

Maybe.
I will have to try…