webgl需手动实现鼠标拾取:先将屏幕坐标映射为ndc坐标(x∈[-1,1], y∈[-1,1]翻转),再通过视图与投影矩阵逆变换生成世界空间射线,最后用möller–trumbore算法检测与三角形相交,并建议用包围体和空间划分优化性能。

WebGL 本身不提供鼠标拾取(Raycasting)功能,需要手动实现射线与物体的相交检测。核心思路是:将鼠标屏幕坐标转为裁剪空间坐标,再逆变换到世界空间生成一条射线,最后检测该射线是否与场景中物体的几何体相交。
将鼠标位置转换为归一化设备坐标(NDC)
浏览器坐标系原点在左上角,而 WebGL 的 NDC 范围是 [-1, 1],需做映射:
- 用
event.clientX / canvas.clientWidth得到 [0, 1] 区间横坐标,再映射为 [-1, 1] - 纵坐标注意翻转:用
1 - event.clientY / canvas.clientHeight再映射到 [-1, 1] - z 值通常设为 -1(近平面)用于构造射线起点,或用 0 表示裁剪空间中的方向向量
构建从相机出发的拾取射线
需要相机的视图矩阵(view)和投影矩阵(projection),常用步骤如下:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 计算 MVP 的逆矩阵(
projection × view的逆),或分别求逆再相乘(viewInverse × projectionInverse) - 将 NDC 坐标(x, y, -1, 1)和(x, y, 1, 1)分别齐次除法后变换到世界空间,得到射线起点和终点
- 用终点减起点归一化,即得世界空间下的单位方向向量
与物体做相交测试(以三角形为例)
若物体使用自定义网格(如顶点数组),需遍历其三角面片,用 Möller–Trumbore 算法判断射线与三角形是否相交:
- 对每个三角形的三个顶点(v0, v1, v2),计算边向量 e1 = v1−v0、e2 = v2−v0
- 计算行列式 det = dot(cross(rayDir, e2), e1),若接近 0 则平行,跳过
- 计算 u、v、t 参数,检查 u≥0、v≥0、u+v≤1 且 t > 0,满足则相交
- 记录最小正 t 对应的物体,即为最近拾取目标
优化拾取性能的实用技巧
直接遍历所有三角形开销大,生产环境建议:
- 为每个可拾取物体维护简化包围体(AABB 或球体),先做粗筛
- 使用空间划分结构(如八叉树或 BVH),加速射线-物体遍历
- 避免每帧重建射线;鼠标移动时只在事件回调中更新一次
- 若用 Three.js 等库,直接调用
Raycaster.intersectObjects(),它已封装上述逻辑
不复杂但容易忽略细节:矩阵顺序、坐标系 handedness(WebGL 默认右手系)、以及 canvas 实际尺寸与 CSS 显示尺寸不一致时需用 getBoundingClientRect() 校准鼠标位置。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










