| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- <template>
- <div ref="container" class="w-full h-full cursor-move" title="Drag to rotate" />
- </template>
- <script setup lang="ts">
- import { ref, onMounted, onUnmounted } from "vue";
- import * as THREE from "three";
- import { STLLoader } from "three/addons/loaders/STLLoader.js";
- import { OrbitControls } from "three/addons/controls/OrbitControls.js";
- interface Props {
- file: File;
- }
- const props = defineProps<Props>();
- const container = ref<HTMLElement | null>(null);
- let animationId = 0;
- onMounted(() => {
- if (!container.value) return;
- const width = container.value.clientWidth || 80;
- const height = container.value.clientHeight || 80;
- const scene = new THREE.Scene();
- const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 2000);
- camera.position.set(0, 0, 150);
- const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
- renderer.setSize(width, height);
- renderer.setClearColor(0x000000, 0); // transparent
- container.value.appendChild(renderer.domElement);
- const controls = new OrbitControls(camera, renderer.domElement);
- controls.enableDamping = true;
- controls.autoRotate = true;
- controls.autoRotateSpeed = 3.0;
- // Add lights
- const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 1);
- hemiLight.position.set(0, 200, 0);
- scene.add(hemiLight);
- const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
- dirLight.position.set(100, 200, 100);
- scene.add(dirLight);
- const loader = new STLLoader();
- const objectUrl = URL.createObjectURL(props.file);
-
- loader.load(objectUrl, (geometry) => {
- geometry.center();
- geometry.computeVertexNormals();
- const material = new THREE.MeshPhongMaterial({
- color: 0x3b82f6,
- specular: 0x111111,
- shininess: 100
- });
-
- const mesh = new THREE.Mesh(geometry, material);
-
- geometry.computeBoundingSphere();
- const radius = geometry.boundingSphere?.radius || 50;
- const scale = 50 / radius;
- mesh.scale.set(scale, scale, scale);
- scene.add(mesh);
- URL.revokeObjectURL(objectUrl);
- });
- const animate = () => {
- animationId = requestAnimationFrame(animate);
- controls.update();
- renderer.render(scene, camera);
- };
- animate();
- const handleResize = () => {
- if (!container.value) return;
- const w = container.value.clientWidth;
- const h = container.value.clientHeight;
- camera.aspect = w / h;
- camera.updateProjectionMatrix();
- renderer.setSize(w, h);
- };
- window.addEventListener("resize", handleResize);
- onUnmounted(() => {
- cancelAnimationFrame(animationId);
- window.removeEventListener("resize", handleResize);
- if (renderer.domElement.parentNode) {
- renderer.domElement.parentNode.removeChild(renderer.domElement);
- }
- renderer.dispose();
- });
- });
- </script>
|