upend/ui/src/components/display/blobs/ModelViewer.svelte

74 lines
2.0 KiB
Svelte

<script lang="ts">
export let src: string;
import { onMount } from "svelte";
let root: HTMLElement;
onMount(async () => {
root.style.height = `${root.clientWidth}px`;
const THREE = await import("three/src/Three");
const THREE_OC = await import("three/examples/jsm/controls/OrbitControls");
const THREE_STL = await import("three/examples/jsm/loaders/STLLoader");
const camera = new THREE.PerspectiveCamera(
70,
root.clientWidth / root.clientHeight
);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(root.clientWidth, root.clientHeight);
root.appendChild(renderer.domElement);
const controls = new THREE_OC.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.1;
controls.enableZoom = true;
controls.autoRotate = true;
controls.autoRotateSpeed = 3;
const scene = new THREE.Scene();
scene.add(new THREE.HemisphereLight(0xffffff, 1.5));
const loader = new THREE_STL.STLLoader();
loader.load(src, (geometry) => {
const material = new THREE.MeshPhongMaterial({
color: 0xdc322f,
specular: 100,
shininess: 70,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const middle = new THREE.Vector3();
geometry.computeBoundingBox();
geometry.boundingBox.getCenter(middle);
mesh.geometry.applyMatrix4(
new THREE.Matrix4().makeTranslation(-middle.x, -middle.y, -middle.z)
);
const largestDimension = Math.max(
geometry.boundingBox.max.x,
geometry.boundingBox.max.y,
geometry.boundingBox.max.z
);
camera.position.z = largestDimension * 2;
});
function animate() {
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
});
</script>
<div class="modelviewer" bind:this={root} />
<style>
.modelviewer {
width: 100%;
}
</style>