Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions packages/model-viewer/src/features/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,13 @@ configuration or device capabilities');

this[$arButtonContainer].classList.remove('enabled');

const objectURL = generateUsdz ? await this.prepareUSDZ() : this.iosSrc!;
let objectURL: string;
try {
objectURL = generateUsdz ? await this.prepareUSDZ() : this.iosSrc!;
} catch (error) {
this[$arButtonContainer].classList.add('enabled');
throw error;
}
const modelUrl = new URL(objectURL, self.location.toString());

if (generateUsdz) {
Expand Down Expand Up @@ -487,15 +493,22 @@ configuration or device capabilities');
}
exportGroup.updateWorldMatrix(false, true);

const arraybuffer = await exporter.parseAsync(exportGroup, {
maxTextureSize: isNaN(this.arUsdzMaxTextureSize as any) ?
Infinity :
Math.max(parseInt(this.arUsdzMaxTextureSize), 16),
});

for (const m of models) {
exportGroup.remove(m);
target.add(m);
let arraybuffer: ArrayBuffer;
try {
arraybuffer = await exporter.parseAsync(exportGroup, {
maxTextureSize: isNaN(this.arUsdzMaxTextureSize as any) ?
Infinity :
Math.max(parseInt(this.arUsdzMaxTextureSize), 16),
});
} finally {
for (const m of models) {
exportGroup.remove(m);
target.add(m);
}
if (shadow != null) {
shadow.visible = visible;
}
updateSourceProgress(1);
}

const blob = new Blob([arraybuffer], {
Expand All @@ -504,12 +517,6 @@ configuration or device capabilities');

const url = URL.createObjectURL(blob);

updateSourceProgress(1);

if (shadow != null) {
shadow.visible = visible;
}

return url;
}
}
Expand Down
40 changes: 40 additions & 0 deletions packages/model-viewer/src/test/features/ar-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {expect} from 'chai';

import {IS_ANDROID, IS_IOS} from '../../constants.js';
import {$openIOSARQuickLook, $openSceneViewer} from '../../features/ar.js';
import {$progressTracker, $scene} from '../../model-viewer-base.js';
import {ModelViewerElement} from '../../model-viewer.js';
import {waitForEvent} from '../../utilities.js';
import {assetPath, rafPasses, spy} from '../helpers.js';
Expand Down Expand Up @@ -143,6 +144,45 @@ suite('AR', () => {
});

suite('openQuickLook', () => {
test(
'restores the viewer after video texture USDZ conversion fails',
async () => {
element.shadowIntensity = 1;
element.src = assetPath('models/cube.gltf');
await waitForEvent(element, 'load');
const texture =
element.createVideoTexture(assetPath('models/lottie-logo.mp4'));
element.model!.materials[0]
.pbrMetallicRoughness.baseColorTexture.setTexture(texture);

const scene = (element as any)[$scene];
const parent = scene.models[0].parent;
const shadowVisible = scene.shadow?.visible;
expect(scene.shadow).to.not.be.null;
expect(shadowVisible).to.be.true;
const button = element.shadowRoot!.querySelector('.ar-button')!;
button.classList.add('enabled');
const progress = (element as any)[$progressTracker];
expect(progress.ongoingActivityCount).to.equal(0);

let thrown: unknown;
try {
await (element as any)[$openIOSARQuickLook]();
} catch (error) {
thrown = error;
}

expect(thrown).to.be.instanceOf(Error);
expect((thrown as Error).message)
.to.include('No valid image data found');
expect([
scene.models[0].parent === parent,
scene.shadow?.visible === shadowVisible,
progress.ongoingActivityCount === 0,
button.classList.contains('enabled'),
]).to.deep.equal([true, true, true, true]);
});

test('sets hash for fixed scale', () => {
element.src = 'https://example.com/model.gltf';
element.iosSrc = 'https://example.com/model.usdz';
Expand Down
Loading