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

Three.js Points对象Raycasting拾取与指针位置不匹配问题

Three.js Points 射线拾取位置不匹配问题修复

核心问题原因

代码存在3处直接导致拾取错位的逻辑错误:

  • 指针归一化基准错误:pointermove事件中用window.innerWidth/innerHeight做坐标换算,但实际渲染canvas并未占满整个窗口,计算出的NDC坐标和相机实际视口不匹配,从输入源就产生了偏移。
  • 拾取判定和渲染逻辑不对齐:自定义了顶点size属性修改点大小,但没有给射线拾取器设置对应匹配的判定阈值,默认拾取范围和屏幕上实际渲染的粒子大小不匹配。
  • 状态初始值bug:INTERSECTED初始值为undefined,第一次触发选中时会访问数组的undefined索引,写入无效数据,同时导致后续选中/未选中的状态切换逻辑异常。

修复方案

  1. 指针坐标换算统一以canvas的实际布局位置、尺寸为基准,不再使用window全局尺寸
  2. 给射线拾取器的Points类型设置匹配粒子尺寸的判定阈值,和渲染逻辑对齐
  3. 修正INTERSECTED初始值为null,补全边界判断,避免访问无效数组索引
  4. 点材质开启sizeAttenuation,保证自定义的size属性计算逻辑和Three.js内置的透视衰减逻辑一致,避免渲染大小和3D空间判定大小脱节。

修复后关键代码

// 修正状态初始值
let particles, raycaster, INTERSECTED = null, pointer
raycaster = new THREE.Raycaster()
pointer = new THREE.Vector2(99999, 99999)

// 绑定canvas引用,修正指针坐标计算
const canvas = document.querySelector('#c')
document.addEventListener('pointermove', (event) => {
  const rect = canvas.getBoundingClientRect()
  pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
  pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1
})
document.addEventListener('pointerout', () => pointer.set(99999, 99999))

// 设置和粒子尺寸匹配的拾取阈值
raycaster.params.Points.threshold = PARTICLE_SIZE / 2

// 修正材质配置,对齐尺寸计算逻辑
let material = new THREE.PointsMaterial({
  color: 0xffffff,
  transparent: true,
  depthTest: true,
  depthWrite: false,
  size: PARTICLE_SIZE,
  sizeAttenuation: true
})
material.onBeforeCompile = shader => {
  shader.vertexShader = shader.vertexShader.replace(
    'uniform float size;',
    'attribute float size;'
  )
}

替换对应代码后,射线拾取结果会和指针实际位置完全匹配,粒子选中放大的交互逻辑也能正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:45:32