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
11 changes: 10 additions & 1 deletion packages/model-viewer/src/model-viewer-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,15 @@ export default class ModelViewerElementBase extends ReactiveElement {
// modified its source set
if (newExtraUrls.join(',') !== currentExtraUrls.join(',') ||
extraModels.length !== currentExtraUrls.length) {
this[$updateSource]();
if (this.src == null && extraModels.length === 0) {
this[$loaded] = false;
this[$loadedTime] = 0;
this[$scene].reset();
} else {
this[$loaded] = false;
this[$loadedTime] = 0;
this[$updateSource]();
}
}
};

Expand All @@ -230,6 +238,7 @@ export default class ModelViewerElementBase extends ReactiveElement {

if (customEv.detail.srcChanged) {
this[$loaded] = false;
this[$loadedTime] = 0;
this[$updateSource]();
} else {
// Apply Transforms
Expand Down
80 changes: 60 additions & 20 deletions packages/model-viewer/src/test/features/extra-model-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,45 @@ suite('ExtraModel', () => {
expect(scene._models.length).to.equal(2);
});

test('removes extra-model and updates the scene', async () => {
element.loading = 'eager';
element.src = CUBE_GLB_PATH;

const extra = document.createElement('extra-model');
extra.setAttribute('src', CUBE_GLB_PATH);
element.appendChild(extra);

await waitForEvent(element, 'load');

const scene = (element as any)[$scene];
expect(scene._models.length).to.equal(2);

const loadEvent = waitForEvent(element, 'load');
element.removeChild(extra);
await loadEvent;

expect(scene._models.length).to.equal(1);
});

test('removes all extra-models when src is null', async () => {
element.loading = 'eager';

const extra = document.createElement('extra-model');
extra.setAttribute('src', CUBE_GLB_PATH);
element.appendChild(extra);

await waitForEvent(element, 'load');

const scene = (element as any)[$scene];
expect(scene._models.length).to.equal(1);

element.removeChild(extra);
await timePasses();

expect(scene._models.length).to.equal(0);
expect(scene.extraUrls.length).to.equal(0);
});

test('updates position dynamically when offset changes', async () => {
element.loading = 'eager';
element.src = CUBE_GLB_PATH;
Expand Down Expand Up @@ -102,31 +141,32 @@ suite('ExtraModel', () => {
expect(scene._models[1].position.x).to.be.closeTo(3, 0.001);
});

test('applies orientation as rotation on the model quaternion', async () => {
element.loading = 'eager';
element.src = CUBE_GLB_PATH;
test(
'applies orientation as rotation on the model quaternion', async () => {
element.loading = 'eager';
element.src = CUBE_GLB_PATH;

const extra = document.createElement('extra-model');
extra.setAttribute('src', CUBE_GLB_PATH);
// yaw = 90deg (third term in roll/pitch/yaw) → Euler(0, π/2, 0, 'YXZ')
// → quaternion.y ≈ 0.707, quaternion.w ≈ 0.707
extra.setAttribute('orientation', '0deg 0deg 90deg');
element.appendChild(extra);
const extra = document.createElement('extra-model');
extra.setAttribute('src', CUBE_GLB_PATH);
// yaw = 90deg (third term in roll/pitch/yaw) → Euler(0, π/2, 0,
// 'YXZ') → quaternion.y ≈ 0.707, quaternion.w ≈ 0.707
extra.setAttribute('orientation', '0deg 0deg 90deg');
element.appendChild(extra);

await waitForEvent(element, 'load');
await waitForEvent(element, 'load');

const scene = (element as any)[$scene];
const q = scene._models[1].quaternion;
expect(q.y).to.be.closeTo(Math.sin(Math.PI / 4), 0.001);
expect(q.w).to.be.closeTo(Math.cos(Math.PI / 4), 0.001);
const scene = (element as any)[$scene];
const q = scene._models[1].quaternion;
expect(q.y).to.be.closeTo(Math.sin(Math.PI / 4), 0.001);
expect(q.w).to.be.closeTo(Math.cos(Math.PI / 4), 0.001);

// Update dynamically
extra.setAttribute('orientation', '0deg 0deg 0deg');
await timePasses();
// Update dynamically
extra.setAttribute('orientation', '0deg 0deg 0deg');
await timePasses();

expect(scene._models[1].quaternion.y).to.be.closeTo(0, 0.001);
expect(scene._models[1].quaternion.w).to.be.closeTo(1, 0.001);
});
expect(scene._models[1].quaternion.y).to.be.closeTo(0, 0.001);
expect(scene._models[1].quaternion.w).to.be.closeTo(1, 0.001);
});

test(
'does not calculate bounding box synchronously when offset changes',
Expand Down
1 change: 1 addition & 0 deletions packages/model-viewer/src/three-components/ModelScene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ export class ModelScene extends Scene {

reset() {
this.url = null;
this.extraUrls = [];
this.renderCount = 0;
this.queueRender();
if (this.shadow != null) {
Expand Down
Loading