1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
| <div ref="container" style="width: 100%; height: 600px; position: relative; top: -300px;" class="threeD"></div> // 导入 Three.js 主模块 import * as THREE from 'three' // 从 three/examples/jsm 目录导入 GLTFLoader(three@0.126.1 已支持ES模块导入) import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
// 导入 OrbitControls 用于交互旋转和缩放 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
data() { return { scene: null, camera: null, renderer: null, loader: null, model: null, controls: null, animationId: null, raycaster: new THREE.Raycaster(), mouse: new THREE.Vector2(), selectedObject: null, } mounted() {
this.initScene(); this.loadModel(); this.animate(); window.addEventListener('resize', this.onResize); this.$refs.container.addEventListener('click', this.onClick, false); }, beforeDestroy() { // 清除窗口事件监听和动画循环 window.removeEventListener('resize', this.onResize); cancelAnimationFrame(this.animationId); if (this.renderer) { this.renderer.dispose(); } }, methods: { // 初始化场景、相机、光照和渲染器,并配置 OrbitControls initScene() { const container = this.$refs.container; const width = container.clientWidth; const height = container.clientHeight;
// 创建场景 this.scene = new THREE.Scene();
// 创建透视相机 this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000); // 设置俯视视角:相机高高在上,y = 20,z = 0 // this.camera.position.set(100, 60, 200); this.camera.position.set(25,15,50); // 让相机朝下看 this.camera.lookAt(new THREE.Vector3(0,0,0)); this.scene.add(this.camera);
// 添加环境光和方向光 const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); this.scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(5, 10, 7.5); this.scene.add(directionalLight);
// 创建渲染器,开启抗锯齿与透明背景 this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); this.renderer.setSize(width, height); container.appendChild(this.renderer.domElement);
// 初始化 OrbitControls 实例,关联相机和渲染器 DOM 元素 this.controls = new OrbitControls(this.camera, this.renderer.domElement); // 开启阻尼效果,提升控制的流畅性 this.controls.enableDamping = true; this.controls.dampingFactor = 0.25; // 允许缩放(可选) this.controls.enableZoom = true; }, // 使用 GLTFLoader 加载 GLB 模型 loadModel() { this.loader = new GLTFLoader(); // 模型文件放在 public/models 目录下 this.loader.load( '/models/model.glb', (gltf) => { this.model = gltf.scene; // 根据需要调整模型的缩放、位置及旋转 this.model.scale.set(1, 1, 1); this.model.position.set(0, 0, 0); this.scene.add(this.model); }, (xhr) => { console.log(`模型加载进度:${(xhr.loaded / xhr.total) * 100}%`); }, (error) => { console.error('加载 GLB 模型出错:', error); } ); }, // 动画循环,更新控制器和渲染场景 animate() { this.animationId = requestAnimationFrame(this.animate); // 更新 OrbitControls,确保交互效果平滑 if (this.controls) { this.controls.update(); } this.renderer.render(this.scene, this.camera); }, // 监听窗口大小变化,调整相机和渲染器 onResize() { const container = this.$refs.container; const width = container.clientWidth; const height = container.clientHeight; this.camera.aspect = width / height; this.camera.updateProjectionMatrix(); this.renderer.setSize(width, height); },
// 点击事件处理 onClick(event) { const rect = this.$refs.container.getBoundingClientRect(); // 计算鼠标点击位置归一化坐标(-1 到 1) this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
this.raycaster.setFromCamera(this.mouse, this.camera);
// 获取所有可拾取的模型子对象 const intersects = this.raycaster.intersectObjects(this.model.children, true);
if (intersects.length > 0) { const selected = intersects[0].object; this.selectedObject = selected;
console.log('点击了对象:', selected.name || selected.uuid);
// 可选:显示提示信息 // alert(`你点击了部件:${selected.name || '未命名对象'}`); } }, } }
|