toji / chrome-webvr-issues

Stub repository for tracking bugs related to Chrome's experimental WebVR support
53 stars 12 forks source link

WebVR 1.0: vrInput.getPose() and overlay semantics #54

Closed vt5491 closed 6 years ago

vt5491 commented 8 years ago

Chromium-WebVR-openVR build from 03-06-2016.

Calling pose.position seems to ignore the previous position of the target object (e.g. the camera) and uses "overlay" (or absolute/destructive) semantics, whereas Firefox uses "update" (or delta/non-destructive) semantics.

It's probably more helpful if I just show you the relevant code.

Here's the section of code from Three.js module VRControls:

this.update = function () {
    if ( vrInput ) {
        if ( vrInput.getPose ) {
            var pose = vrInput.getPose();

            if ( pose.orientation !== null ) {
                object.quaternion.fromArray( pose.orientation );
            }

            if ( pose.position !== null ) {
                object.position.fromArray( pose.position ).multiplyScalar( scope.scale ); <- note this line
            }
        } else {

The object in question that is being updated is whatever object you attached to the VRControls, which is almost always the camera:

this.controls = new THREE.VRControls(this.camera);

If the camera is at position x=10, let's say, and the head tracker returns -0.1, then Chromium sets the x position of the camera to be 0.1, not 9.9 like Firefox. At times in the past Chromium has worked the same as Firefox, using "update" semantics, instead of it's current "overlay" semantics.

Either method is justifiable, it's just that with overlay semantics, I have to keep track of my camera's logical position and manually add it each time:

factory.updateScene = function() {
  // This basically extracts the rotation and position from the Rift and puts
  // it into the cameras rotation and position.  We previously defined the VRControl
  // to be attached to our camera.
  this.controls.update();  // this is all I have to do with Firefox, and some older versions of Chromium

  //vt add
  // with "overlay" semantics I have to do the following
  // I also need to have my code update "logialCamera" instead of the "physical" camera
  // on camera move events
  this.camera.position.add(this.camera.logicalCamera.position);

  this.camera.rotation.x += this.camera.logicalCamera.rotation.x;
  this.camera.rotation.y += this.camera.logicalCamera.rotation.y;
  this.camera.rotation.z += this.camera.logicalCamera.rotation.z;

The nice thing about update semantics is I just need one set of coordinates and rotations to keep track of my camera -- that of the camera's position and rotation itself.

With overlay semantics, if I don't add in the logical camera's coordinates, my camera always hovers around zero, and all keyboard events have no effect.

Does this make sense? This is more of an empirical than a theoretical finding. Was this done intentionally? Why does Firefox work the other way? I, and I think most developers, would prefer "update" semantics.

toji commented 8 years ago

I think the issue you're seeing may be in how you're using Three.js, but let's dig into it a bit.

To start, WebVR should ALWAYS return position, orientation, and acceleration in absolute terms. Specifically, position is always reported as relative to the current "origin", which is whatever position the user's head was in when the app last called VRDisplay.resetPose. If any browser is returning poses relative to the last frame they are doing it wrong. (And it may be worth adding a little bit more explicit language to the spec about this.) I don't think Firefox is returning delta values, though, and I know Chrome isn't.

That's why I think the issue is with your use of Three.js' VRControls. When you attach an object to a VRControls that object's position/orientation is overridden by the WebVR provided position/orientation. So if you set your camera position to (10, 10, 0) and then attach it to a VRControls object then next frame will replace that camera position with whatever WebVR reports, which is likely to be a much smaller number. This is normal, and how VRControls is intended to work. (Though it confused me at first as well.)

Of course, it's not always desired to have the user stuck at the origin of your scene. So if you want to move the user around and have they're head position be relative to a position you control, the solution is to attach the camera to a "dolly" object, like so:

var dolly = new THREE.Object3D();
dolly.position.x = 10;
dolly.position.y = 10;
scene.add( dolly );

/* Create camera, then... */
dolly.add( camera );
var controls = new THREE.VRControls( camera );

Now your camera position and rotation will be relative to the dolly, which you can use to apply other controls. See the Three.js WebVR Rollercoaster for a working example of this.

vt5491 commented 8 years ago

Thank you for your response. I really like your recommendation about using a dolly. It makes perfect sense and I will use it going forward.

But that still leaved the question in my mind, and this is perfectly reproducible on my system, as to why Firefox worked as expected (didn't overlay position) and Chromium didn't.

I investigate further, and believe I have found the problem.

First off, I should note that on my DK2 setup I don't even plug the positional camera in at all, since it's a pain to position and I'm interested in a seated VR experience only. So it's pretty obvious that the only info I get is rotational not positional (at least it's obvious now... I don't know why it wasn't obvious to me before).

Well, to make a long story short, by putting in few log statements I determined that Firefox is returning 'null' for state.position, and Chromium is returning a DOMPoint object with fields set to zero. The object update statement in VRControls only occurs if pose.position is not null:

        if ( pose.position !== null ) {
            object.position.fromArray( pose.position ).multiplyScalar( scope.scale ); <- note this line
        }

Thus Chromium drives the code, and overlays, and Firefox skips and leaves my user coordinates.

So if there's any vagueness in the specification, it's in what should be returned if the HDM positional tracker is not there -- should it return a 'null' or a DOMPoint with 0. Firefox went with 'null', and Chromium used to go with 'null', but is now going with DOMPoint. I suppose you could also consider three use cases of "no positional data":

A) not plugged in at all -> arguably you might use a 'null' in this case B) plugged in, but not active -> probably returning DOMPoint with zero's is best here C) plugged in, working, and actually at point 0 -> Definitely want to return DOMPoint

Those are the three use cases, that you could choose to use 'null' or zero DOMPoint as your response (not that this is really my domain). It doesn't really matter to me, as long as there is a standard and everyone follows it.

So I was just getting lucky with my code before in that when there was no positional data, I was still OK.

After I update my code to use the dolly method, that should address the problem.

Thanks again for your feedback.

capnmidnight commented 8 years ago

Positional tracking is still important for seated experiences. On Mar 29, 2016 8:56 PM, "vt5491" notifications@github.com wrote:

Thank you for your response. I really like your recommendation about using a dolly. It makes perfect sense and I will use it going forward.

But that still leaved the question in my mind, and this is perfectly reproducible on my system, as to why Firefox worked as expected (didn't overlay position) and Chromium didn't.

I investigate further, and believe I have found the problem.

First off, I should note that on my DK2 setup I don't even plug the positional camera in at all, since it's a pain to position and I'm interested in a seated VR experience only. So it's pretty obvious that the only info I get is rotational not positional (at least it's obvious now... I don't know why it wasn't obvious to me before).

Well, to make a long story short, by putting in few log statements I determined that Firefox is returning 'null' for state.position, and Chromium is returning a DOMPoint object with fields set to zero. The object update statement in VRControls only occurs if pose.position is not null:

    if ( pose.position !== null ) {
        object.position.fromArray( pose.position ).multiplyScalar( scope.scale ); <- note this line
    }

Thus Chromium drives the code, and overlays, and Firefox skips and leaves my user coordinates.

So if there's any vagueness in the specification, it's in what should be returned if the HDM positional tracker is not there -- should it return a 'null' or a DOMPoint with 0. Firefox went with 'null', and Chromium used to go with 'null', but is now going with DOMPoint. I suppose you could also consider three use cases of "no positional data":

A) not plugged in at all -> arguably you might use a 'null' in this case B) plugged in, but not active -> probably returning DOMPoint with zero's is best here C) plugged in, working, and actually at point 0 -> Definitely want to return DOMPoint

Those are the three use cases, that you could choose to use 'null' or zero DOMPoint as your response (not that this is really my domain). It doesn't really matter to me, as long as there is a standard and everyone follows it.

So I was just getting lucky with my code before in that when there was no positional data, I was still OK.

After I update my code to use the dolly method, that should address the problem.

Thanks again for your feedback.

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/toji/chrome-webvr-issues/issues/54#issuecomment-203175198

vt5491 commented 8 years ago

capnmidnight, yes I totally agree with you. Positional tracking while seated is still needed e.g. for looking around an object, to the side etc.

I'm not using positional tracking because I don't think it's a good idea. It's just another bunch of cords I could do without for now. And lately, I've been using an OSVR headset anyway, and positional tracking doesn't work on it (at least when I first set it up).

toji commented 6 years ago

Closing all bugs in this issue tracker.

This repo was created to track issues in the experimental builds WebVR Chromium builds, which are now deprecated. Chrome Canary for Windows now has much more secure (and hopefully more performant) support for WebVR behind a flag, and Android has had WebVR support as an Origin Trial and behind a flag for a while now.

If this is a performance or correctness bug and you suspect it's still happening, please test against the latest Canary build of Chrome to verify and then file a bug at https://crbug.com. If this is an issue with the API, please review the latest WebXR explainer to see if it's been resolved and file a bug there if not.

Thanks for your interest in VR on the web! We've got an exciting year ahead of us! --Brandon