才想起来自己还有个csdn账号需要维护,顺手记录一下最近在写three.js中踩到的坑。
在 Three.js 中,射线拾取(raycasting)是一种用于检测用户鼠标与三维场景中的对象交互的方法。这在实现鼠标点击选择、碰撞检测或交互式功能时非常有用。
其原理图大概如下所示:
当我们在用射线拾取three.js中的物体时,往往会遇到拾取精度问题:
1、画布大小为适配
2、需要设置与各种物体相交时的精度因子
第1个问题比较好解决,以下代码就可以解决问题了
const getRayIntersectsAction = (boxNode, intersectObjects, event) => {
let getBoundingClientRect = boxNode.getBoundingClientRect();
mouse.x = ((event.clientX - getBoundingClientRect.left) / boxNode.offsetWidth) * 2 - 1;
mouse.y = - ((event.clientY - getBoundingClientRect.top) / boxNode.offsetHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
return raycaster.intersectObjects(intersectObjects, true);
}
而最近工作中我遇到了第二个问题。拾取线段精度不准确。
具体就是在遇到渲染Line2或者LineSegements2后拾取有精度差,此时根据网上资料搜到的设置
linePrecision并不能解决问题。
笔者用到LineSegements2是因为需要渲染大量不连续的线段,而LineSegements2虽然和LineSegements只差一个字,实现的方法大大不同,LineSegements继承了Line,而Line2则是继承了LineSegements2,在webgl的渲染中,为了渲染带宽度的线段,往往会选择Line2。
three.js提供的两种线,Line 和 Line2 有所区别。前者只支持宽度为1的线,后者则支持任意线宽。
按照官方示例,可以很容易绘制出已确定顶点位置的线要素(静态的线)
然而很多时候我们都需要动态的往线要素里添加新的顶点,网上查了很多资料,大体思路都是构造新的几何体(LineGeometry)替换已有线对象的几何体,然后重新设置点位(line.geometry = new LineGeometry(); line.geometry.setPositions(positions););或是移除原有的线,然后构造新的线对象。这两种方式原理相似,如果在频繁加入顶点的情况下,会造成明显的性能问题。
LineSegements2本质上都是BufferGeometry用实例化的方式渲染。使用three.js绘制不连续的线段重要的其实是使用LineSegmentsGeometry,然后使用setPositions,setColors的方式去渲染着色。如果使用了LineSegements2,使用射线拾取时,精度问题很大,看源码可以发现
影响拾取精度的竟然是raycaster.params.Line2.threshold的值!当你没设置时为0!!
接下来只要修改raycaster.params.Line2.threshold = 1或者合适的值即可。不同的几何体最好阅读其源码去设置。