【问题标题】:THREE.Raycaster inaccurate results三、Raycaster结果不准确
【发布时间】:2020-08-01 17:53:34
【问题描述】:

我正在制作2D scatterplot with a tooltip,目前检测某个点何时悬停的光线投射器已损坏。工具提示仅在触摸对象时激活,这是正确的行为,但它显示来自在 x/y 平面上甚至不接近的点的完全随机数据,并且即使没有其他点靠近该对象也会更改信息盘旋在上方。谁能帮我调试这种行为?下面是一些相关代码(其余的可以在上面的链接中找到):

...loading in points (stored in data_points array), creating scene, etc.

raycaster = new THREE.Raycaster();
raycaster.params.Mesh.threshold = 20;

view.on("mousemove", () => {
    let [mouseX, mouseY] = d3.mouse(view.node());
    let mouse_position = [mouseX, mouseY];
    checkIntersects(mouse_position);
});
function mouseToThree(mouseX, mouseY) {
    return new THREE.Vector3(
        mouseX / viz_width * 2 - 1,
        -(mouseY / height) * 2 + 1,
        1
    );
}
function checkIntersects(mouse_position) {
    let mouse_vector = mouseToThree(...mouse_position);
    raycaster.setFromCamera(mouse_vector, camera);
    let intersects = raycaster.intersectObjects(scene.children, true);
    if (intersects[0]) {
        let sorted_intersects = sortIntersectsByDistanceToRay(intersects);
        let intersect = sorted_intersects[0];
        let index = intersect.faceIndex;
        let datum = data_points[index];
        showTooltip(mouse_position, datum);
    } else {
        hideTooltip();
    }
}
function sortIntersectsByDistanceToRay(intersects) {
    return _.sortBy(intersects, "distanceToRay");
}

...tooltip functions, details

任何帮助将不胜感激。谢谢!

【问题讨论】:

    标签: javascript d3.js three.js


    【解决方案1】:

    为什么要使用d3.mouse(view.node()); 来获取鼠标位置?看起来这会给你带来疯狂的结果。在一个很小的空间中移动指针时,我得到一个从 2200 到 -97 的 X 范围,此时它应该相隔几个像素。

    我建议您在 mousemove 上使用默认的 JavaScript 方法 event.clientX and event.clientY 获得确切的 XY 屏幕位置

    看这个例子,taken directly from a Three.js Raycasting example

    function onMouseMove( event ) {
        mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
        mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
        raycaster.setFromCamera( mouse, camera );
    }
    

    另外,我建议通过 CSS 移除文档边距,这样您的测量值就不会偏离几个像素。

    【讨论】:

    • 添加了这个实现,请再次在同一链接上查看我的代码。问题显然在于鼠标缩放,因为 x 和 y 从 -1 变为 1,这与我的文档不同。
    • 光线投射器就是这样工作的。 x = -1 是画布的左侧,x = 1 是右侧。然后,它应用相机投影并将其转换为 3D 射线,以检查与其相交的对象。
    【解决方案2】:

    想出了答案。我的数据点没有合适的“索引”变量(THREE.Group 由 [THREE.Mesh, THREE.LineLoop] 组成),这就是为什么光线投射有效但点选择无效(不要使用 faceIndex)。所以我在网格的 userData 字段下创建了一个。

    // Create circle geometries
    for (var i=0; i<data_points.length; i++) {
        // Circle
        let geo = new THREE.CircleBufferGeometry(data_points[i].radius, 32);
        let mat = new THREE.MeshBasicMaterial( {color: color_array[data_points[i].label] } );
        let mesh = new THREE.Mesh(geo, mat);
        mesh.userData.id = i;
    
        ...lineLoop and Group code
    }
    
    ...more code
    
    function onMouseMove(event) {
        mouseRay.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
        mouseRay.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
        mouseRay.z = 1;
        let mouse = [event.clientX, event.clientY];
        raycaster.setFromCamera(mouseRay, camera);
        let intersects = raycaster.intersectObjects(scene.children, true);
        if (intersects[0]) {
            let sorted_intersects = sortIntersectsByDistanceToRay(intersects);
            console.log(sorted_intersects);
            let intersect = sorted_intersects[0];
            // Here is the change I made!!!
            let index = intersect.object.userData.id;
            let datum = data_points[index];
            highlightPoint(datum);
            showTooltip(mouse, datum);
        } else {
            removeHighlights();
            hideTooltip();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-01-04
      • 2015-06-17
      • 1970-01-01
      • 1970-01-01
      • 2020-12-16
      • 2021-04-15
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      相关资源
      最近更新 更多