diff --git a/src/App.vue b/src/App.vue
index 5f07b1b..55b03bf 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -55,7 +55,7 @@ for (let model of settings.preloadModels) {
Tools
-
+
diff --git a/src/models/glb/merge.ts b/src/models/glb/merge.ts
index 7a86d99..787835b 100644
--- a/src/models/glb/merge.ts
+++ b/src/models/glb/merge.ts
@@ -15,7 +15,7 @@ export async function mergePartial(glb: Uint8Array, name: string, document: Docu
let newDoc = await io.readBinary(glb);
// noinspection TypeScriptValidateJSTypes
- // await newDoc.transform(dropByName(name), setNames(name));
+ await newDoc.transform(dropByName(name), setNames(name));
let merged = document.merge(newDoc);
diff --git a/src/tools/Tools.vue b/src/tools/Tools.vue
index 69c8bee..ebcf07a 100644
--- a/src/tools/Tools.vue
+++ b/src/tools/Tools.vue
@@ -3,15 +3,16 @@ import {VBtn} from "vuetify/lib/components";
import {ref} from "vue";
import OrientationGizmo from "./OrientationGizmo.vue";
import {OrthographicCamera} from "three/src/cameras/OrthographicCamera";
-import {mdiCrosshairsGps, mdiProjector} from '@mdi/js'
+import {mdiCrosshairsGps, mdiCursorDefaultClick, mdiDownload, mdiProjector} from '@mdi/js'
import SvgIcon from '@jamescoyle/vue-icon';
-import {SceneManagerData} from "../misc/scene";
-import type {ModelViewerElement} from '@google/model-viewer';
+import type {ModelViewerElement, RGBA} from '@google/model-viewer';
+import type {Material} from '@google/model-viewer/lib/features/scene-graph/material.js';
+import {SceneMgrRefData} from "../misc/scene";
-let props = defineProps<{ sceneMgrData: SceneManagerData }>();
+let props = defineProps<{ refSData: SceneMgrRefData }>();
function syncOrthoCamera(force: boolean) {
- let scene = props.sceneMgrData.viewerScene;
+ let scene = props.refSData.viewerScene;
if (!scene) return;
let perspectiveCam = (scene as any).__perspectiveCamera;
if (force || perspectiveCam && scene.camera != perspectiveCam) {
@@ -28,7 +29,7 @@ function syncOrthoCamera(force: boolean) {
let toggleProjectionText = ref('PERSP'); // Default to perspective camera
function toggleProjection() {
- let scene = props.sceneMgrData.viewerScene;
+ let scene = props.refSData.viewerScene;
if (!scene) return;
let prevCam = scene.camera;
let wasPerspectiveCamera = prevCam.isPerspectiveCamera;
@@ -44,32 +45,76 @@ function toggleProjection() {
}
function centerCamera() {
- let viewer: ModelViewerElement = props.sceneMgrData.viewer;
+ let viewer: ModelViewerElement = props.refSData.viewer;
if (!viewer) return;
viewer.updateFraming();
}
+let selectionEnabled = ref(false);
+let prevHighlightedMaterial: Material | null = null;
+let hasListener = false;
+let selectionListener = (event: MouseEvent) => {
+ if (!selectionEnabled.value) return;
+ let viewer: ModelViewerElement = props.refSData.viewer;
+ const material = viewer.materialFromPoint(event.clientX, event.clientY);
+ if (material !== null && prevHighlightedMaterial?.index === material.index) return
+ if (prevHighlightedMaterial) {
+ prevHighlightedMaterial.pbrMetallicRoughness.setBaseColorFactor(
+ (prevHighlightedMaterial as any).__prevBaseColorFactor);
+ }
+ if (!material) {
+ prevHighlightedMaterial = null;
+ return;
+ }
+ (material as any).__prevBaseColorFactor = [...material.pbrMetallicRoughness.baseColorFactor];
+ material.pbrMetallicRoughness.setBaseColorFactor([1, 0, 0, 1] as RGBA);
+ prevHighlightedMaterial = material;
+};
+
+function toggleSelection() {
+ let viewer: ModelViewerElement = props.refSData.viewer;
+ if (!viewer) return;
+ selectionEnabled.value = !selectionEnabled.value;
+ if (selectionEnabled.value) {
+ if (!hasListener) {
+ viewer.addEventListener('mousemove', selectionListener);
+ hasListener = true;
+ }
+ } else {
+ if (prevHighlightedMaterial) {
+ prevHighlightedMaterial.pbrMetallicRoughness.setBaseColorFactor(
+ (prevHighlightedMaterial as any).__prevBaseColorFactor);
+ prevHighlightedMaterial = null;
+ }
+ }
+}
+
+async function downloadSceneGlb() {
+ let viewer = props.refSData.viewer;
+ if (!viewer) return;
+ const glTF = await viewer.exportScene();
+ const file = new File([glTF], "export.glb");
+ const link = document.createElement("a");
+ link.download = file.name;
+ link.href = URL.createObjectURL(file);
+ link.click();
+}
+
-
+
{{ toggleProjectionText }}
-
-
+
+
-
-
-
-
-
-
-
-
+
+
diff --git a/src/viewer/ModelViewerWrapper.vue b/src/viewer/ModelViewerWrapper.vue
index 36732e8..c59e329 100644
--- a/src/viewer/ModelViewerWrapper.vue
+++ b/src/viewer/ModelViewerWrapper.vue
@@ -1,13 +1,13 @@