Search code examples
three.jswebvr360-virtual-realityhtc-vive

three.js equirectangular video shaking in vive headset


I render an equirectangular video on the three.js sphere and test the performance of Chromium WebVR on VIVE.

I notice that the video vibrates and shakes when I look around in VIVE. That makes me feel dizzy.

If I replace video to image, the vibration stop. I test different videos, every video vibrate. So maybe the problem happens when three.js tries to render these videos on the sphere.

I also check the fps. It's around 85~90 fps. Looks pretty good.

( Before that, I've test the same script on mobile using WebVR Boilerplate and watch video in Cardboard, it works fine. No shaking and vibration. The fps is around 50. )

While I'm testing, I accidentally figure out if I put an sphere in three.js example webvr_vive_sculp.html, the vibration reduce. Also the fps reduce to 50~60. If I limited the fps in my original script, nothing change.

Did anyone face this problem?

Here's my script:

<!DOCTYPE html>
<html lang="en">
    <head>
    <title>360 video in vive</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>

        body {

        background-color: #000000;
        margin: 0px;
        overflow: hidden;
        }

        #info {
            position: absolute;
            top: 0px; width: 100%;
            color: #ffffff;
            padding: 5px;
            font-family:Monospace;
            font-size:13px;
            font-weight: bold;
            text-align:center;
        }

        a {
            color: #ffffff;
        }
    </style>
</head>
<body>

    <div id="container"></div>


    <script src="../build/three.js"></script>
    <script src="js/controls/VRControls.js"></script>
    <script src="js/effects/VREffect.js"></script>
    <script src="js/vr/ViveController.js"></script>
    <script src="js/vr/WebVR.js"></script>


    <script>
        if ( WEBVR.isAvailable() === false ) {

            document.body.appendChild( WEBVR.getMessage() );

        }


        var camera, scene, renderer;
        var effect, controls;
        var video;

        init();
        animate();

        function init() {

            var container, mesh;

            container = document.getElementById( 'container' );


            camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
            camera.target = new THREE.Vector3( 0, 0, 0 );

            controls = new THREE.VRControls( camera );
            controls.standing = true;

            scene = new THREE.Scene();

            // 360 video
            video      = document.createElement('video');
            video.autoplay = true;
            video.src    = 'video/8Kevil_3840x1920_hq.webm'; // 'video/Danger in the Room.webm' // 8Kevil_3840x1920_hq
            video.crossOrigin = '';
            videoTexture = new THREE.Texture(video);
            videoTexture.minFilter = THREE.LinearFilter;
            videoTexture.magFilter = THREE.LinearFilter;
            videoTexture.format = THREE.RGBFormat;

            // 360 video sphere   
            var cubeGeometry = new THREE.SphereGeometry(500, 60, 40);
            var sphereMat = new THREE.MeshBasicMaterial({map: videoTexture});
            sphereMat.side = THREE.BackSide;
            var cube = new THREE.Mesh(cubeGeometry, sphereMat);
            scene.add(cube);

            renderer = new THREE.WebGLRenderer();
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer.setSize( window.innerWidth, window.innerHeight );
            container.appendChild( renderer.domElement );



            effect = new THREE.VREffect( renderer );
            if ( WEBVR.isAvailable() === true ) {

                document.body.appendChild( WEBVR.getButton( effect ) );

            }
            window.addEventListener( 'resize', onWindowResize, false );

        }

        function onWindowResize() {

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize( window.innerWidth, window.innerHeight );

        }

        function animate() {

            effect.requestAnimationFrame( animate );
            update();

        }

        function update() {
            if( video.readyState === video.HAVE_ENOUGH_DATA ){
                videoTexture.needsUpdate = true;
            }

            controls.update();
            effect.render( scene, camera );

        }

    </script>
</body>



Solution

  • WebVr does not handle video textures well right now, if you pause the video the flickering stops right ?

    You can try Firefox nightly, it handles video textures a little bit better, and has lower latency in general.

    You can test it by opening the vive menu during the experience and shaking your head, in Chrome you'll notice much more latency between Vive's native menu performance and your experience in the dimmed background.

    Try to usevideoTexture.minFilter = THREE.NearestFilter; and videoTexture.maxFilter = THREE.NearestFilter;

    For the sphere use new THREE.SphereGeometry(500, 720, 4); I know it looks weird, but this way you'll get much smoother stitches on top/bottom of the sphere.