一、目的
为了在前端页面展示3d打印机打印过程
二、前期准备
完整模型的stl文件和模型切割成的n个stl文件
models文件夹下的文件就是切割后的stl文件
三、代码
<template><div ref="threeContainer" class="three-container"></div></template><script>import * as THREE from "three";import { STLLoader } from "three/examples/jsm/loaders/STLLoader.js";import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";export default {name: "CastleDemo",mounted() {this.initThree();},methods: {initThree() {const scene = new THREE.Scene();scene.background = new THREE.Color(0xeeeeee);const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);camera.position.set(0, 20, 50); // 调整相机位置,使其离模型更远camera.lookAt(scene.position);const renderer = new THREE.WebGLRenderer({ antialias: true });renderer.setSize(window.innerWidth, window.innerHeight);this.$refs.threeContainer.appendChild(renderer.domElement);const ambientLight = new THREE.AmbientLight(0x404040, 1);const pointLight = new THREE.PointLight(0xffffff, 1, 1000);pointLight.position.set(0, 50, 50);scene.add(ambientLight, pointLight);const loader = new STLLoader();const models = this.generateModels(); // 生成47个模型的配置// 状态变量:控制是否开始旋转let allModelsLoaded = false;// 逐层加载模型let currentModelIndex = 0;const loadNextModel = () => {if (currentModelIndex < models.length) {const model = models[currentModelIndex];loader.load(model.url, (geometry) => {geometry.center();const material = new THREE.MeshStandardMaterial({color: model.color,transparent: true, // 启用透明度opacity: 0.8, // 设置透明度值});const mesh = new THREE.Mesh(geometry, material);mesh.position.set(...model.position);mesh.scale.set(model.scale, model.scale, model.scale);scene.add(mesh);// 动态更新进度currentModelIndex++;loadNextModel();});} else {// 所有模型加载完成allModelsLoaded = true;}};loadNextModel(); // 开始加载第一个模型// 添加轨道控制器const controls = new OrbitControls(camera, renderer.domElement);controls.enableDamping = true; // 启用阻尼效果controls.dampingFactor = 0.25; // 阻尼系数controls.enableZoom = true; // 允许缩放controls.enablePan = true; // 允许平移// 添加旋转逻辑let rotationSpeed = 0.01; // 旋转速度function animate() {requestAnimationFrame(animate);// 只有在所有模型加载完成后才开始旋转if (allModelsLoaded) {scene.traverse((object) => {if (object.isMesh) {object.rotation.y += rotationSpeed; // 绕Y轴旋转object.rotation.x += rotationSpeed * 0.5; // 绕X轴旋转}});}controls.update(); // 更新轨道控制器renderer.render(scene, camera);}animate();},// 生成47个模型的配置generateModels() {const models = [];const basePosition = [0, -36.5, 0]; // 基础位置,从底部开始const spacing = 0.5; // 模型之间的间距for (let i = 0; i < 72; i++) { const position = [basePosition[0], // X轴位置basePosition[1] + i * spacing, // Y轴方向排列,从低到高basePosition[2],];const color = this.getColorByIndex(i); // 根据索引计算颜色models.push({url: `/3Dmodels/castledemo/models/part_${String(i).padStart(6, "0")}.stl`, // 文件名格式为 part_000000.stl 到 part_000046.stlposition,scale: 0.3,color,});}return models;},// 根据索引计算颜色getColorByIndex(index) {const startColor = 0xffff00; // 起始颜色为黄色const endColor = 0x00ffff; // 结束颜色为青色const colorRange = endColor - startColor;const ratio = index / (47 - 1); // 计算颜色比例const color = startColor + Math.floor(colorRange * ratio);return color;},},};</script><style scoped>.three-container {background-color: #ffffff;}</style>
四、最终效果
五、问题
模型重构出来会存在走位的情况,可能需要根据每个模型文件的实际大小进行调整。