如何在Three.js r144中用BufferGeometry实现鼠标拖拽自由画线?
问题:Three.js r144下拖拽绘制线条功能失效
将基于Three.js r87的scribble代码升级到r144后,mousePressed函数已正常更新,但mouseDragged函数无法实现鼠标拖拽绘制线条的功能。
已正常工作的mousePressed代码:
function mousePressed() { const point = new THREE.Vector3(mouseX, mouseY, 0); // const geometry = new THREE.Geometry(); // geometry.vertices.push(point); let points = []; points.push(point); let geometry = new THREE.BufferGeometry().setFromPoints(points); const line = new THREE.Line(geometry, material); scene.add(line); selected = line; }
失效的mouseDragged代码:
function mouseDragged() { const line = selected; const point = new THREE.Vector3(mouseX, mouseY, 0); const oldgeometry = line.geometry; // const newgeometry = new THREE.Geometry(); // newgeometry.vertices = oldgeometry.vertices; // newgeometry.vertices.push(point); let newgeometry = new THREE.BufferGeometry(); let positions = oldgeometry.attributes.position.array; for (let i = 0; i < positions.length; i += 3) { const v = new THREE.Vector3(positions[i], positions[i + 1], positions[i + 2]); positions[i] = v.x; positions[i + 1] = v.y; positions[i + 2] = v.z; } positions.push(point); // I should just be able to add the new point, no? newgeometry.attributes.position.needsUpdate = true; line.geometry = newgeometry; scene.add(line); // I re-added the line, just in case. But the line does not show up, whether or not I do this. selected = line; }
解决方案
mouseDragged函数存在几个关键问题:
BufferGeometry的position.array是TypedArray(如Float32Array),不能直接用push添加元素,需创建新的TypedArray扩容- 空的
newgeometry未赋值任何位置数据,直接替换原geometry会导致线条无数据渲染 - 无需重新创建BufferGeometry,直接更新现有线条的geometry即可,也不用重新添加到场景
修正后的mouseDragged代码:
function mouseDragged() { if (!selected) return; // 避免未选中线条时触发报错 const line = selected; const point = new THREE.Vector3(mouseX, mouseY, 0); const geometry = line.geometry; // 获取现有位置数据 const oldPositions = geometry.attributes.position.array; // 创建新的Float32Array,长度为旧数据+3个新坐标(x/y/z) const newPositions = new Float32Array(oldPositions.length + 3); // 复制旧数据到新数组 newPositions.set(oldPositions); // 追加新点的坐标 newPositions[oldPositions.length] = point.x; newPositions[oldPositions.length + 1] = point.y; newPositions[oldPositions.length + 2] = point.z; // 更新geometry的position属性 geometry.setAttribute('position', new THREE.BufferAttribute(newPositions, 3)); // 标记位置数据需要更新 geometry.attributes.position.needsUpdate = true; }
关键说明:
- 使用
Float32Array管理位置数据,符合Three.js BufferGeometry的标准格式 - 通过
set方法复制旧数据,再追加新坐标,保证数据结构正确 - 直接更新现有geometry的
position属性,无需替换整个geometry或重复添加到场景 - 增加
!selected判断,避免未点击创建线条前拖拽导致的报错
内容的提问来源于stack exchange,提问作者astro_bear
相关产品推荐
相关产品推荐

