import * as THREE from 'three'; import { TransformControls } from 'three/examples/jsm/controls/TransformControls'; // 引入模块 import * as dat from "dat.gui"; let modal, cubeList:THREE.Mesh[] = [], curve, line //创建gui对象 const gui = new dat.GUI(); gui.domElement.style.top = '300' gui.domElement.style.clientTop = 300 gui.domElement.style.zIndex = 9999 // 画点 const addCube = (initialPoints, scene) => { return initialPoints.map(pos => { const geometry = new THREE.BoxBufferGeometry(1, 1, 1); const material = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide }); const cube = new THREE.Mesh(geometry, material); cube.position.copy(pos); scene.add(cube); cubeList.push(cube) // gui.add(cube.position, 'x', -1000, 1000) // gui.add(cube.position, 'y', -1000, 1000) // gui.add(cube.position, 'z', -1000, 1000) }); } // 画线 export const drawLine = (initialPoints, obj) => { modal = obj addCube(initialPoints, modal.scene) curve = new THREE.CatmullRomCurve3( cubeList.map((cube) => cube.position) // 直接绑定方块的position以便后续用方块调整曲线 ); curve.curveType = 'chordal'; // 曲线类型 curve.closed = false; // 曲线是否闭合 const points = curve.getPoints(50); // 50等分获取曲线点数组 line = new THREE.LineLoop( new THREE.BufferGeometry().setFromPoints(points), new THREE.LineBasicMaterial({ color: 0xffffff, linewidth: 10 }) ); // 绘制实体线条,仅用于示意曲线,后面的向量线条同理,相关代码就省略了 modal.scene.add(line); addChangeEvent() } // 获取点击位置 const addChangeEvent = () => { debugger const control = new TransformControls(modal.camera, modal.renderer.domElement); // 获取点击位置 const mouse = new THREE.Vector2(); window.addEventListener( 'click', (event) => { debugger mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // mouse.x = ((event.clientX - dom.offsetLeft) / dom.clientWidth) * 2 - 1; // dom.offsetLeft -- dom元素距离浏览器左侧的距离 dom.clientWidth -- dom元素宽度 // mouse.y = -((event.clientY - dom.offsetTop) / dom.clientHeight) * 2 + 1; // dom.offsetTop -- dom元素距离浏览器顶部的距离 dom.clientHeight -- dom元素高度 //根据照相机,把这个向量转换到视点坐标系 const vector = new THREE.Vector3(mouse.x, mouse.y, 0.5).unproject(modal.camera); // 方块点击检测 // const rayCaster = new THREE.Raycaster(); //在视点坐标系中形成射线,射线的起点向量是照相机, 射线的方向向量是照相机到点击的点,这个向量应该归一标准化。 const rayCaster = new THREE.Raycaster(modal.camera.position, vector.sub(modal.camera.position).normalize()); // rayCaster.setFromCamera(mouse, modal.camera); const intersects = rayCaster.intersectObjects(cubeList); if (intersects.length) { const target = intersects[0].object; control.attach(target); // 绑定controls和方块 modal.scene.add(control); } }, false ); // 修改曲线后同步修改实体线条 control.addEventListener('dragging-changed', (event) => { if (!event.value) { console.log(event.value); const points = curve.getPoints(50); line.geometry.setFromPoints(points); } }); }