Description:
The requestPresent from within the vrdisplayactivate is failing on Oculus Browser (and I bet on Chrome too) due to the wrong layer provided. The commit that introduced the issue is a3ac58e4084053c14706abc6ef37bde45086a33e. See https://github.com/aframevr/aframe/blob/b3ed182fefb883e36272401529a8b5a3b1a9ce5d/src/utils/device.js#L13: it creates a new non-gl canvas, and tries to use it as a layer, which is not going to work. Even in the nested requestPresents you must specify the ACTUAL GL canvas, not just a placeholder (https://immersive-web.github.io/webvr/spec/1.1/#dom-vrdisplay-requestpresent%E2%91%A0)
Seems like the previous version worked (or should have worked).
Changing it back to
`window.addEventListener('vrdisplayactivate', function (evt) {
// WebXR takes priority if available.
if (navigator.xr) { return; }
let sceneEl = document.querySelector('a-scene');
let canvasEl = sceneEl.canvas;
vrDisplay = evt.display;
// Request present immediately. a-scene will be allowed to enter VR without user gesture.
vrDisplay.requestPresent([{source: canvasEl}]).then(function () {}, function () {});
});`
seems to fix the issue.
@Artyom17 Thanks for taking a look, much appreciated. The placeholder canvas is passed to honor the time limit that WebVR implementations have to call requestPresent after vrdisplayactivate fires. At that point in time the scene and final canvas might not be initialized. Will initializing the webgl context with the placeholder canvas work? Does Oculus not support multiple calls to requestPresent with different canvases?
Oh thanks for the suggestion. We just crossed comments and I didn鈥檛 see yours. I鈥檒l try what you suggest. Thank you.
Yeah, Oculus does support multiple calls with different canvases (at least it should, I need to double test it). But the issue with the rejected requestPresent is that the canvas you provide is not the WebGL one.
@Artyom17 your solution won鈥檛 work. That canvas might not be initialized when vrdisplayactivate fires.
Yeah, understood, I am leaving this to you to figure out the proper solution ;) You just need to use the webgl-canvas, that is it (i.e. the webgl context should be associated with the canvas).
Thanks. Would just initializing a webgl context on the placeholder canvas work?
It could.... I can try it really quick. But will you switch canvases later on to the actual one?
Yeah, it works in terms of entering VR, but nothing renders (I assume, because the wrong canvas is used for the rendering). It seems like the second issue here.
The idea is that when the scene is properly initialized we will call requestPresent again with the final canvas we will use to render the scene. The place holder is used to render a loading screen.
I see...But do you?
Ok, let me check...
Something weird is happening. If I put two requestPresent with different canvases in a row, one after another - everything works.
When I call requestPresent in activedisplay and then from a-scene - only white background is rendered (i.e. some rendering occurs, such as clear)....
@Artyom17 Does Firefox desktop works with the same code (it also implements vrdisplayactivate on navigation)? That would probably help determine if the problem is in A-Frame or Oculus Browser side. Thanks for looking at this. I know it can be tricky to investigate.
if it helps i tested https://a-frobot.github.io/aframe/examples/showcase/link-traversal/ on oculus go with Firefox Reality and does not work ( black window after link traversal after resume white window)
Not sure if VR navigation actually works on Firefox Reality. Firefox and Supermedium on desktop are the ones that do.
LOL, I don't even have a Rift connected to my work desktop (should I mention that the main OS for me is Linux? ;) )
Anyway, the issue with rendering is caused by the cameras' viewports in renderObjects are not setup correctly (all NaNs).
Cameras viewports are not set correctly, because WebVRManager.renderWidth and renderHeight are not set correctly. Those supposed to be set in WebVRManager.onVRDisplayPresentChange.
However, the method isPresenting() returns false, because WebVRManager.setDevice method wasn't called from the ondisplayactivate. Also, note, that even if the 'device' is set, the device.isPresenting property will be false till promise of the requestPresent is satisfied (and currently, this fact is completely ignored in ondisplayactivate).
And I am not sure how to access WebVRManager from utils/device.js....
if i am not wrong it should be
var sceneEl = document.querySelector('a-scene');
sceneEl.renderer.vr
https://github.com/aframevr/aframe/blob/master/src/core/scene/a-scene.js#L258
Ok, in this case this rough mod makes things to render in Oculus Browser with deeplinking / navigation:
```
window.addEventListener('vrdisplayactivate', function (evt) {
// WebXR takes priority if available.
if (navigator.xr) { return; }
let canvasEl = document.createElement('canvas');
let vrDisplay = evt.display;
// Request present immediately. a-scene will be allowed to enter VR without user gesture.
let glAttribs = {
alpha: false,
antialias: true
};
canvasEl.getContext("webgl", glAttribs);
vrDisplay.requestPresent([{source: canvasEl}]).then(function () {
let sceneEl = document.querySelector('a-scene');
sceneEl.renderer.vr.setDevice(vrDisplay);
}, function () {});
});
Problem is similar there. We cannot rely on sceneEl.renderer to be ready when vrdisplayactivate fires the first time. My understanding is that the root issue is that vrdisplaypresentchange only fires once after the first requestPresent call and we're missing the event later on, resulting in WebVRManager not setting renderWidth / renderHeight accordingly.
Yes, it does fire only once, you are right.
Not sure what would be the spec compliant behavior. Should vrdisplaypresentchange fire for all successful calls to requestPresent?
onvrdisplaypresentchange A user agent MUST dispatch this event type to indicate that a VRDisplay has begun or ended VR presentation. This event should not fire on subsequent calls to requestPresent() after the VRDisplay has already begun VR presentation.
(https://immersive-web.github.io/webvr/spec/1.1/#window-vrdisplaypresentchange-event)
Ok, thanks. It seems ww need to find a way to run the logic from onVRDisplayPresentChange in WebVRManager after the second call to requestPresent. That and initializing a webgl context on the first dummy canvas should fix the issues.
If you have the code handy (not with the Quest at the moment). Can you try emitting a synthetic event when second call to requestPresent succeeds?
var event = new CustomEvent('vrdisplaypresentchange', { detail: { display: utils.device.getVRDisplay()} });
window.dispatchEvent(event);
I think this should fix the issue. Probably here: https://github.com/aframevr/aframe/blob/master/src/core/scene/a-scene.js#L312
k, let me try
@dmarcos - yup, seems like that made the trick. Do you want me to create PR with both of these changes, or you'll do it yourself?
Yeah feel free to open a PR. It will be super appreciated. Thank you very much.
Most helpful comment
Ok, thanks. It seems ww need to find a way to run the logic from
onVRDisplayPresentChangein WebVRManager after the second call torequestPresent. That and initializing a webgl context on the first dummy canvas should fix the issues.