Skip to content

Commit

Permalink
Enable viewport scaling, fix view assumptions (google#1613)
Browse files Browse the repository at this point in the history
* Use view's viewport, enable autoscaling

Loop over the returned view array instead of just using the first view,
and use each view's corresponding viewport.

Also use dynamic viewport scaling using the recommended viewport scale
if supported.

* Add getViewport to mock XRSession state

Co-authored-by: Emmett Lalish <[email protected]>
  • Loading branch information
klausw and elalish authored Oct 16, 2020
1 parent 3e43c54 commit 23a0ed9
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ class MockXRFrame implements XRFrame {
projectionMatrix: camera.projectionMatrix.elements as unknown as
Float32Array,
viewMatrix: {} as Float32Array,
transform: transform
transform: transform,
recommendedViewportScale: null,
requestViewportScale: (_scale: number|null) => {}
};
const viewerPos: XRViewerPose = {transform: transform, views: [view]};

Expand Down Expand Up @@ -95,7 +97,9 @@ suite('ARRenderer', () => {
const stubWebXrInterface = (arRenderer: ARRenderer) => {
arRenderer.resolveARSession = async () => {
class FakeSession extends EventTarget implements XRSession {
public renderState: XRRenderState = {baseLayer: {} as XRLayer} as
public renderState: XRRenderState = {baseLayer: {
getViewport: () => { return {x: 0, y: 0, width: 320, height: 240} as XRViewport }
} as XRLayer} as
XRRenderState;

public hitTestSources: Set<XRHitTestSource> =
Expand Down
44 changes: 33 additions & 11 deletions packages/model-viewer/src/three-components/ARRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ const INTRO_DAMPER_RATE = 0.4;
const SCALE_SNAP_HIGH = 1.2;
const SCALE_SNAP_LOW = 1 / SCALE_SNAP_HIGH;

// For automatic dynamic viewport scaling, don't let the scale drop below this limit.
const MIN_VIEWPORT_SCALE = 0.25;

export type ARStatus =
'not-presenting'|'session-started'|'object-placed'|'failed';

Expand Down Expand Up @@ -457,6 +460,15 @@ export class ARRenderer extends EventDispatcher {
this.dispatchEvent({type: 'status', status: ARStatus.SESSION_STARTED});
}

// Use automatic dynamic viewport scaling if supported.
if (view.requestViewportScale && view.recommendedViewportScale) {
const scale = view.recommendedViewportScale;
view.requestViewportScale(Math.max(scale, MIN_VIEWPORT_SCALE));
}
const layer = this[$currentSession]!.renderState.baseLayer;
const viewport = layer!.getViewport(view);
this.threeRenderer.setViewport(viewport.x, viewport.y, viewport.width, viewport.height);

this[$presentedScene]!.model.orientHotspots(
Math.atan2(cameraMatrix.elements[1], cameraMatrix.elements[5]));
}
Expand Down Expand Up @@ -744,20 +756,30 @@ export class ARRenderer extends EventDispatcher {
return;
}

this[$updateCamera](pose.views[0]);
// WebXR may return multiple views, i.e. for headset AR. This
// isn't really supported at this point, but make a best-effort
// attempt to render other views also, using the first view
// as the main viewpoint.
let isFirstView: boolean = true;
for (const view of pose.views) {
this[$updateCamera](view);

this[$placeInitially](frame);
if (isFirstView) {
this[$placeInitially](frame);

this[$processInput](frame);
this[$processInput](frame);

const delta = time - this[$lastTick]!;
this[$moveScene](delta);
this.renderer.preRender(scene, time, delta);
this[$lastTick] = time;
const delta = time - this[$lastTick]!;
this[$moveScene](delta);
this.renderer.preRender(scene, time, delta);
this[$lastTick] = time;
}

// NOTE: Clearing depth caused issues on Samsung devices
// @see https://github.com/googlecodelabs/ar-with-webxr/issues/8
// this.threeRenderer.clearDepth();
this.threeRenderer.render(scene, this.camera);
// NOTE: Clearing depth caused issues on Samsung devices
// @see https://github.com/googlecodelabs/ar-with-webxr/issues/8
// this.threeRenderer.clearDepth();
this.threeRenderer.render(scene, this.camera);
isFirstView = false;
}
}
}
2 changes: 2 additions & 0 deletions packages/model-viewer/src/types/webxr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ declare interface XRView {
readonly projectionMatrix: Float32Array;
readonly viewMatrix: Float32Array;
readonly transform: XRRigidTransform;
readonly recommendedViewportScale: number|null;
requestViewportScale(scale: number|null): void;
}

declare interface XRViewerPose {
Expand Down

0 comments on commit 23a0ed9

Please sign in to comment.