Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ar #77

Merged
merged 4 commits into from
Nov 8, 2018
Merged

Fix ar #77

merged 4 commits into from
Nov 8, 2018

Conversation

cdata
Copy link
Contributor

@cdata cdata commented Nov 6, 2018

AR now works in iOS Safari 12+ and Web XR-capable Chrome Canary on Android.

Video recording of AR on Pixel 2

Video recording of AR on iPad Mini / iOS 12

Notable changes include:

  • A new ARRenderer has been added, that is modeled after the old ARView
  • Renderer incorporates ARRenderer and exposes its public API to Renderer consumers. I don't love this approach, but it seemed like the easiest factoring to start with. Open to suggestions
  • More resilient capability checks and more informative error messaging has been incorporated throughout ARRenderer
  • screenful has been replaced with a Fullscreen API polyfill approach, so that we just rely on standard APIs in the implementation
  • Fullscreen API and Intersection Observer polyfills have been selected for recommendation and usage in examples and tests
  • I had to go back to Chrome Canary 70.0.3538.2 (~September '18) on Android before I could reliably get XR hits

Test status on OSX:

image

Test status on iOS 12 Safari:

image

Fixes #55

@cdata cdata force-pushed the fix-ar branch 3 times, most recently from c247f3a to 21958b6 Compare November 7, 2018 04:01
@cdata cdata requested a review from jsantell November 7, 2018 04:24
@cdata cdata changed the title (WIP) Fix ar Fix ar Nov 7, 2018
Copy link
Contributor

@jsantell jsantell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, thanks Chris! This is a tricky area to get right. Handful of comments about WebXR and some caveats I'm aware of.
One thing that bit me before (and I think it'll be easier to wrangle with current architecture) was changing scales between inline and AR (where inline is sized to a specific dimension, and AR is unmodified scale), and back to inline. Check out scaleModelToFitRoom() and resetModelPose() in ModelScene

<script src="../node_modules/resize-observer-polyfill/dist/ResizeObserver.js"></script>

<!-- Fullscreen polyfill is required to support all stable browsers: -->
<script src="../node_modules/fullscreen-polyfill/dist/fullscreen.polyfill.js"></script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a future idea, it'd be cool to test our example pages for all appropriate polyfills

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 #81

@@ -8,7 +8,7 @@
"dist"
],
"scripts": {
"clean": "rm -r ./lib ./dist",
"clean": "rm -rf ./lib ./dist",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beat me to it 😆

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍻

console.log('Attempting to enter fullscreen and present in AR...');

try {
const enterFullscreen = this.requestFullscreen();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no browsers shipping with unprefixed/normalized fullscreen API -- this seems less like a 'bring your own polyfills to choose browser support' scenario and more like one we should normalize on our end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although this is only used for WebXR mode. If we had a fullscreen feature for all models, I'd feel strongly about including a fullscreen API normalizer, but if it's just for WebXR, it's less critical.

Copy link
Contributor Author

@cdata cdata Nov 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thoughts on this:

  • It is a classic case where a polyfill should be used (as opposed to every library normalizing it everywhere).
  • The polyfill is only needed for the Web XR case, which right now is a niche / experimental case
  • If you don't count Web XR, Chrome stable requires zero polyfills. This seems like a reasonable litmus test for whether we should ask for a polyfill or bundle some kind of normalization.

.map((element, index) => {
return (index === 0) === element[$scene].isVisible;
})
.reduce(((l, r) => l && r), true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


const $onWebXRFrame = Symbol('onWebXRFrame');
const $onOutputCanvasClick = Symbol('onOutputCanvasClick');
const $onFullscreenchange = Symbol('onFullscreenchange');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This instance isn't accessible to developers; we could get away with less "private" properties, or maybe combine several under a $state object in categories, e.g. all three.js scene components under the same $scene object or something. Just an idea, too many symbols can hurt readability IMO

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed 👍will tone down the symbol usage

src/utils.js Outdated
@@ -17,6 +17,45 @@ import {Vector3} from 'three';

export const deserializeUrl = (url) => url != null ? toFullUrl(url) : url;

export const HAS_WEBXR_DEVICE_API = navigator.xr != null &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd make a note that these can be true on Chrome release if the correct flags are set, even though there is no ARCore bridge shipping on that platform, and that these are only hints.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will document

// NOTE: This is needed in tests so that we don't have to manually trigger
// the IntersectionObserver polyfill in Safari. Ordinarily, it would be
// triggered by a resize or scroll event.
// @see https://github.com/w3c/IntersectionObserver/tree/master/polyfill#configuring-the-polyfill
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙀

this[$renderer].setSize(window.innerWidth, window.innerHeight);
this[$renderer].setPixelRatio(1);
this[$renderer].autoClear = false;
this[$renderer].gammaInput = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gammaInput can be removed (and is also being removed from three?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix

this[$currentSession] = null;
session.cancelAnimationFrame(this[$rafId]);

await session.end();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After end()ing the session, we should defer to an end event on XRSession: https://immersive-web.github.io/webxr/#dom-xrsession-onend

The session can abort on its own accord and will need to clean it up when that happens

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if the end event is called, ultimately we'll get a error while trying to end AR session for attempting to re-destroy it -- same result, but maybe would be better to have this execute the ending of the session, and an onEnd that cleans up everything else (which manually calling session.end() will call the event anyway, leading to the same path for both scenarios)

});
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext(
'webgl', {antialias: true, alpha: true, preserveDrawingBuffer: true});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be aggressive about only enabling alpha and preserveDrawingBuffer if we think there's a good chance of WebXR support, otherwise will have unneeeded overhead in 95% scenarios

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, will fix

@jsantell
Copy link
Contributor

jsantell commented Nov 7, 2018

Also, were there any other issues on iOS devices that you've found? (I haven't tried in months)

@cdata
Copy link
Contributor Author

cdata commented Nov 8, 2018

@jsantell responded to the feedback. PTAL!

if (!buttonIsVisible) {
this[$enterARElement].style.display = 'none';
if (iosCandidate ||
(canShowButton && await renderer.supportsPresentation())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

much nicer

const gl = this.renderer.getContext();

await gl.setCompatibleXRDevice(device);
session.baseLayer = new XRWebGLLayer(session, gl, {alpha: true});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this third argument is necessary (and already configured on the context)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. Just copied this configuration from ARView FWIW.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah there's been a handful of changes over the months inconsistently applied in demos due to platforms or discoveries across a handful of projects so I was extra cautious about all the old code I wrote months ago 😄

this.camera.updateMatrixWorld(true);
// NOTE: Clearing depth caused issues on Samsung devices
// @see https://github.com/googlecodelabs/ar-with-webxr/issues/8
this.renderer.clearDepth();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for leaving this? This can be safely removed (as far as AR consequences go) and only prevents Samsung devices from working

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oversight, will fix


import {isMobile} from '../utils.js';
import {IS_AR_CANDIDATE} from '../constants.js';
// import {IS_MOBILE} from '../constants.js';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will remove

// Only enable certain options when Web XR capabilities are detected:
if (IS_AR_CANDIDATE) {
Object.assign(
webGlOptions, {antialias: true, preserveDrawingBuffer: true});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

antialias is redundant here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but i think you'll need alpha -- unless adding that in XRWebGLLayer solves that? I didn't think that was something you could change after instantiation, but if this works, great

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug, actually. Should be alpha.

this[$currentSession] = null;
session.cancelAnimationFrame(this[$rafId]);

await session.end();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if the end event is called, ultimately we'll get a error while trying to end AR session for attempting to re-destroy it -- same result, but maybe would be better to have this execute the ending of the session, and an onEnd that cleans up everything else (which manually calling session.end() will call the event anyway, leading to the same path for both scenarios)

const presentedScene = this[$presentedScene];

const x = 0;
const y = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is not using click coords, should make a note that it fires it out from the center of the screen

@cdata cdata merged commit 2f4cbd2 into master Nov 8, 2018
@cdata cdata deleted the fix-ar branch November 8, 2018 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants