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

Three.js:通过鼠标点击与移动创建/更新Mesh

Got it, let's tackle moving your click-to-add-points + mouse-follow functionality from a Line to a Mesh in Three.js. Here's how to approach it step by step:

迁移到Mesh实现点击添加顶点+鼠标跟随功能

First, a key difference to note: unlike Lines that only need a sequence of points, Meshes rely on faces (triangles/quads) to render. So we can't reuse your Line's point array logic directly—we'll need to handle face indices alongside vertex positions.

1. Initialize the Core Structure

We'll need to track three key pieces of data: fixed vertices added via clicks, a temporary vertex that follows the mouse, and face indices to define the Mesh's geometry.

// Track fixed vertices and the mouse-following temp vertex
const fixedPoints = [];
const tempPoint = new THREE.Vector3();

// Create dynamic BufferGeometry
const geometry = new THREE.BufferGeometry();
// Pre-allocate space for positions (avoids frequent resizing)
const positions = new Float32Array(1000 * 3); // Supports up to 1000 points
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
// Pre-allocate space for face indices (each triangle uses 3 indices)
const indices = new Uint32Array(1000 * 3);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));

// Create a debug-friendly material (adjust to your needs)
const material = new THREE.MeshBasicMaterial({
  color: 0x00ff00,
  side: THREE.DoubleSide, // Render both sides of faces
  wireframe: true // Optional: helps visualize vertices/faces during testing
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

2. Handle Mouse Clicks: Add Fixed Vertices & Build Faces

Each click will lock the current temp vertex into the fixed points array, then generate a new triangular face using the latest three points.

function onMouseClick(event) {
  // Save the temp vertex to fixed points
  fixedPoints.push(tempPoint.clone());
  const totalFixedPoints = fixedPoints.length;

  // Update positions array with the new fixed point
  const positionsArray = geometry.attributes.position.array;
  tempPoint.toArray(positionsArray, (totalFixedPoints - 1) * 3);

  // Add a new triangular face if we have at least 3 fixed points
  if (totalFixedPoints >= 3) {
    const indicesArray = geometry.index.array;
    // Index for the new face's start
    const faceStartIndex = (totalFixedPoints - 3) * 3;
    // Assign indices for the triangle: [prev-prev, prev, new point]
    indicesArray[faceStartIndex] = totalFixedPoints - 3;
    indicesArray[faceStartIndex + 1] = totalFixedPoints - 2;
    indicesArray[faceStartIndex + 2] = totalFixedPoints - 1;
    // Update draw range for indices to include the new face
    geometry.index.setDrawRange(0, (totalFixedPoints - 2) * 3);
  }

  // Update draw range for positions and mark attributes as needing updates
  geometry.attributes.position.setDrawRange(0, totalFixedPoints);
  geometry.attributes.position.needsUpdate = true;
  geometry.index.needsUpdate = true;
}
window.addEventListener('click', onMouseClick);

3. Handle Mouse Movement: Update the Temporary Vertex

This part mirrors your Line logic, but we'll also adjust the latest face's index to follow the temp vertex as it moves.

function onMouseMove(event) {
  // Convert mouse position to normalized device coordinates (-1 to 1)
  const mouse = new THREE.Vector2();
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  // Raycast to get 3D position on a target plane (adjust plane to your scene)
  const raycaster = new THREE.Raycaster();
  raycaster.setFromCamera(mouse, camera);
  const targetPlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); // XY plane at z=0
  const intersection = new THREE.Vector3();
  raycaster.ray.intersectPlane(targetPlane, intersection);

  // Update the temp vertex with the intersection point
  tempPoint.copy(intersection);

  const totalFixedPoints = fixedPoints.length;
  const positionsArray = geometry.attributes.position.array;

  if (totalFixedPoints === 0) {
    // No fixed points yet: just update the first position slot
    geometry.attributes.position.setDrawRange(0, 1);
    tempPoint.toArray(positionsArray, 0);
  } else {
    // Update the temp vertex slot (right after fixed points)
    tempPoint.toArray(positionsArray, totalFixedPoints * 3);
    geometry.attributes.position.setDrawRange(0, totalFixedPoints + 1);

    // If we have 2+ fixed points, update the latest face's third index to track the temp point
    if (totalFixedPoints >= 2) {
      const indicesArray = geometry.index.array;
      const lastFaceThirdIndex = (totalFixedPoints - 2) * 3 + 2;
      indicesArray[lastFaceThirdIndex] = totalFixedPoints;
      geometry.index.needsUpdate = true;
    }
  }

  geometry.attributes.position.needsUpdate = true;
}
window.addEventListener('mousemove', onMouseMove);

4. Key Notes for Smooth Implementation

  • Face Logic Flexibility: The example uses triangular faces that build outward with each new point. If you need quad faces or a different shape, adjust how you generate indices.
  • Performance: Pre-allocating large arrays (like 1000 points) avoids the overhead of resizing buffers repeatedly.
  • Material Tweaks: If you switch from wireframe to a solid material, run geometry.computeVertexNormals() to ensure proper lighting.
  • Initial State: Meshes can't render with fewer than 3 vertices. You might want to hide the mesh until the third click, or pair it with a Points object to show the temp vertex early on.

内容的提问来源于stack exchange,提问作者spfuller

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:16:14