You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 21:01:05