Three.js: renderer.setSize ignored when presenting in WebVR

Created on 1 Feb 2018  路  13Comments  路  Source: mrdoob/three.js

I'm trying to increase the render scale when WebVR rendering is enabled. I'm able to see clearly the effects of changing renderScale when using this example - https://webvr.info/samples/test-slow-render.html?heavyGpu=1&cubeScale=0.3&workTime=12&standardSize=true&renderScale=2.0 but when I try to do something similar with renderer.setSize in my code, my custom renderScale is just ignored.

Example:

  1. Upon initialization
    renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(10, 10); // Set to 10px as purely a test
  2. Enable WebVR using WebVR.js example code
  3. Note that the actual WebVR renderer canvas size is something closer or exactly window.innerWidth and window.innerHeight

It seems as though the WebVR renderer is overriding my custom canvas sizing. Is there a better way to control the render scaling during WebVR use?

Three.js version
  • [x] r89
Browser
  • [x] Chrome
OS
  • [x] Android

Most helpful comment

I think this is something which should be allowed with a threejs API. The WebVR 1.1 spec if only a recommended width/height and should be able to vary freely.

Also the new WebXR Devices API spec does explicitly add support for scaling in two ways: for the backbuffer, and rendered viewport (some details to still be worked out):
https://immersive-web.github.io/webxr/spec/latest/#dom-xrwebgllayerinit-framebufferscalefactor
https://immersive-web.github.io/webxr/spec/latest/#dom-xrwebgllayer-requestviewportscaling

All 13 comments

The way the WebVR API is in control of the render size.

It seems as though the WebVR renderer is overriding my custom canvas sizing. Is there a better way to control the render scaling during WebVR use?

You could render into a WebGLRenderTarget and then use that as a texture. That only works for doing lower resolution though, we can't do much about higher resolution at the moment.

The way the WebVR API is in control of the render size.

So it's not currently possible to raise the render scale if using the official WebVR api, correct?

For some use-cases which aren't pushing the performance limits of WebGL it would be really nice to be able to easily render the eye textures at higher resolutions. It appears that the render scale is currently defaulting somewhere around .5 of native which is quite noticeable in a headset.

When I tried to use the code from https://webvr.info/samples/test-slow-render.html and manually set the canvas size using:

var leftEye = vrDisplay.getEyeParameters("left");
var rightEye = vrDisplay.getEyeParameters("right");
var renderWidth = Math.max(leftEye.renderWidth, rightEye.renderWidth);
var renderHeight = Math.max(leftEye.renderHeight, rightEye.renderHeight);
webglCanvas.width = renderWidth * 2 * 2;
webglCanvas.height = renderHeight * 2;

It did change the render size, but the eye placement/offset was then broken. It's likely that the test-slow-render.html example is doing something that I haven't properly ported. Any ideas what that could be? Thanks!

So it's not currently possible to raise the render scale if using the official WebVR api, correct?

We could consider adding a setPixelRatio() to renderer.vr, but... even if the current API kind of allows it, as far as I know, the future versions of the API won't.

We could consider adding a setPixelRatio() to renderer.vr, but... even if the current API kind of allows it, as far as I know, the future versions of the API won't.

Interesting. As far as I know, all of the native desktop and mobile VR SDK's allow for manually setting the render scale for the eye textures. Bummer that the WebVR API wouldn't allow it.

I think this is something which should be allowed with a threejs API. The WebVR 1.1 spec if only a recommended width/height and should be able to vary freely.

Also the new WebXR Devices API spec does explicitly add support for scaling in two ways: for the backbuffer, and rendered viewport (some details to still be worked out):
https://immersive-web.github.io/webxr/spec/latest/#dom-xrwebgllayerinit-framebufferscalefactor
https://immersive-web.github.io/webxr/spec/latest/#dom-xrwebgllayer-requestviewportscaling

renderer.vr.setPixelRatio()
renderer.vr.scaleFactor

馃

New WebXR samples (https://immersive-web.github.io/webxr-samples/) have an example for each framebuffer (static, at init before have canvas) and viewport (dynamic) scaling.

Quick question on this - I was playing around with a Rift in Firefox yesterday and the render scale was much better than what I see in Chrome for Daydream devices. Is that just based on the HMD parameters that those devices are sending? It seems like this might only be an issue for Daydream then, in which case I'll need to have HMD specific conditions for the renderScale - totally fine on my end, but just wanted to make sure I understand what's going on.

Yes... For performance reasons, Daydream creates a canvas that is 0.7 the full resolution.

WebVR 2.0 (WebXR) has an option to overwrite that value, so you'll be able to force 1.0 or more.

I'll try to put that in during the next few weeks.

This is related to my earlier thread https://github.com/mrdoob/three.js/issues/12997 which I have closed to continue here.

It is possible to use a resolution other than the 'standard' resolution if set up before or on VRDisplayPresentChange; for one way see my code modification to three.js in that thread.
Basically, mrdoob's renderer.vr.setPixelRatio(). I would still like to see this in three.js.

It is not possible to change it while presenting. It used to be possible to change resolution dynamically by (1) stopping presentation, (2) change resolution, (3) re-request presentation, but this no longer works in Chrome on Windows. (not sure if that is a SteamVR change or a Chrome change)

Also note that SteamVR now gives a much higher suggested resolution for Vive, probably to match the Vive Pro but also applying to the old Vive. It is probably that change that dustinkerstein saw on Firefox. BUT SteamVR does now offer a per application way to modify resolution.

Thanks @sjpt - I added an ugly hack inside of onVRDisplayPresentChange:

if(device.displayName.indexOf('Google') > -1) {
   renderWidth = parseInt(renderWidth * 1.5);
   renderHeight = parseInt(renderHeight * 1.5);
}   

As I'm currently only enabling VR for Daydream devices (no PolyFill) I'm not worried about whether the devices can handle it as all Daydream compatible devices are on the high end and my GPU requirements are on the lowish end. Definitely would love to see full support for this in Three.js though :)

FYI, I filed a spec request at https://github.com/immersive-web/webxr/issues/349 since I think the new WebXR framebufferScaleFactor is hard to use correctly. I'd appreciate feedback there both from the framework point of view and for people using it - I think a simple relative scale factor where 1.0 means use the default would be much more useful than the current behavior, and also more consistent with WebXR 1.1 where this would correspond with multiplying the renderWidth/renderHeight for getting the canvas size.

Side note, please avoid redefining or overriding devicePixelRatio for VR/XR. Those APIs generally use unscaled pixels with a ratio of 1.0. Any adjustments to that should be independent of the window.devicePixelRatio, that's 3.5 on my phone and accidentally plugging that in as a framebufferScaleMultiplier would be unhelpful.

Was this page helpful?
0 / 5 - 0 ratings