Search code examples
javascriptthree.jswebvr

WebVR Boilerplate Problems - Manager not rendering in VRMode, Camera looks straight down, fullscreen renders only half of window


I'm trying to implement WebVR into a project that I've built in Three.js and I'm having difficulties getting it to function correctly.

A number of problems arise when I view the scene.

  1. When VRMode is false my scene renders but when switching to VR Mode the scene suddenly stops rendering. I can see the two stereoscopic windows but nothing else appears.

  2. When I load my scene on desktop the camera points straight down. Upon loading over a device the scene is flipped upside down. I am telling the camera to look at the center of my image and it doesn't seem to have any effect. It was working just fine before I fiddled with the controls and rendering to support the WebVR manager and VRControls.

        camera.position.set(-300, -800, 200);
        camera.up = new THREE.Vector3(0, 0, 1);
        camera.lookAt(new THREE.Vector3(0, 0, 0));
    

I am able to set the position fine.

  1. When I click the fullscreen button on the bottom of the GUI the screen splits into two halves. The top half is black (my body bg and clearfix color is blue) and the lower half renders my scene. I have an event listener that works fine when I manually resize the window so this has to be related to the VR manager.

Any idea what could be causing these errors?

Here is how I define my renderer:

var width = window.innerWidth,
    height = window.innerHeight;

var renderer = new THREE.WebGLRenderer({
        antialias: true
});

renderer.setSize(width, height);
renderer.setClearColor(0x1D76BB, 1);

// Effect and Controls for VR
effect = new THREE.VREffect(renderer);
controls = new THREE.VRControls(camera);
effect.setSize(width, height);


var manager = new WebVRManager(renderer, effect);

Here is a my animate function:

function animate() {

        requestAnimationFrame(animate);

        if (controls) {
            controls.update();
        }

        if (manager.isVRMode()) {
            renderer.setRenderTarget(null); // add this line
            manager.render(scene, camera);
        } else {
            renderer.render(scene, camera);
        }

    }

My libraries came fresh from bower this morning so I know they are all up to date.


Solution

  • It's hard to guess what's going on without looking at the rest of your code.

    I'm not sure if this is related, but the latest version of the WebVRManager class takes care of switching between VR and non-VR mode for you and it falls back to a normal renderer in 2D mode. So you don't need to check for isVRMode anymore and you don't need to call renderer.render. Just use manager.render and it will do the work for you. The manager now also handles resizing for you, so you probably shouldn't be doing that either. Other than that, you seem to be using the manager correctly.

    VRControls (in conjunction with webvr-polyfill, if you're using it) overrides the camera position and orientation, so setting it yourself will have no effect (unless you're overriding it after controls.update, in which case, the controls will have no effect). If you want to set the base camera transform, you can attach the camera to a "dolly" and set the dolly's transform instead:

    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
    var dolly = new THREE.Object3D();
    dolly.add(camera);
    dolly.position.z = 200;
    dolly.up = new THREE.Vector3(0, 0, 1);
    dolly.lookAt(new THREE.Vector3(0, 0, 0));
    dolly.rotateOnAxis(new THREE.Vector3(0, 1, 0), Math.PI);
    scene.add(dolly);
    
    function animate(timestamp) {
        var timer = new Date().getTime() * 0.0002;
        dolly.position.x = Math.floor(Math.cos(timer) * 600);
        dolly.position.y = Math.floor(Math.sin(timer) * 600);
        controls.update();
        manager.render(scene, camera, timestamp);
        requestAnimationFrame(animate);
    }
    

    Note that you have to add the dolly to the scene and that you have to rotate the dolly on its Y axis, after you make it lookAt something since cameras look into the negative Z direction by default.

    It may also be helpful to add an AxisHelper to the scene so that you can get a better sense of your bearings while you debug:

    var axisHelper = new THREE.AxisHelper(200);
    axisHelper.position.z = 100;
    scene.add(axisHelper);
    

    Lastly, if you are using webvr-polyfill, it can sometimes, depending on which devices you are using, render its own barrel distortion shader pass. So, if your project involves shaders, they might conflict with this shader pass and prevent your scene from rendering correctly, or at all, in VR mode. If this is the case, you may be able to workaround this by rendering your shaders before you call manager.render as I've described here: https://stackoverflow.com/a/32549777/22417