Three.js 从鼠标位置投射光线

Posted

技术标签:

【中文标题】Three.js 从鼠标位置投射光线【英文标题】:Three.js Raycast off from mouse position 【发布时间】:2014-07-24 23:21:41 【问题描述】:

我目前正在使用 three.js 和一些 jQuery 构建一个应用程序。我目前正在投射光线并在光线投射的位置放置一个助手。我或多或少正在努力实现 this.

我已经设法实现了这一点,但是在移动我的对象的坐标并将相机移动到新位置时,我的光线投射或至少助手已关闭。从 here

中可以看出,它似乎偏离了大约 30 像素,但取决于您更改相机角度

这是用于光线投射的助手和 onMouseMove 事件的代码。

// RAYCAST HELPER
            var geometry = new THREE.CylinderGeometry( 0, 5, 15, 3 ); // radius at top, radius at bottom, height, segments
            //geometry.applyMatrix( new THREE.Matrix4().makeTranslation( -50, 0, 0 ) );
            geometry.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI / 2 ) );
            helper = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( color: 0xEB1515, ambient: 0xEB1515, wireframe: false ) );
            scene.add( helper );
            rays = true;

    function onMouseMove( event ) 
                    //console.log("Mouse moved");
                    $( document ).ready(function() 
                    if ( rays == true ) 

                        cX = event.clientX - $( "#info" ).width()
                        cY = event.clientY - $( "#topbar" ).height()

                        mouseVector.x = 2 * ( cX / canvaswidth ) - 1;
                        mouseVector.y = 1 - 2 * ( cY / canvasheight );
                        mouseVector.z = 1;

                        var raycaster = projector.pickingRay( mouseVector.clone(), camera );

                        for (var i = 0; i < buildingsroofs.length; i++) 
                            var intersects = raycaster.intersectObject( buildingsroofs[i]);

                            // Toggle rotation bool for meshes that we clicked
                            if ( intersects.length > 0 ) 
                                console.log("Intersection");
                                helper.position.set( 0, 0, 0 );
                                helper.lookAt( intersects[ 0 ].face.normal );
                                helper.position.copy(intersects[0].point);
                             
                        
                     //End of overarching if loop
                ) 
             //End of onMouse function

有趣的是,我已经让它工作了here,但是这些对象的坐标与我所追求的不同。您还可以看到我正在调整顶部 div 和侧面 div 的高度,因此这似乎不是我最初想象的问题。

【问题讨论】:

【参考方案1】:

由于其他一切都是正确的,与您的 WebGL 画布相比,您的 mouseVector xy 值(即 clientXclientY)很可能是关闭的(例如,您可能会得到这些来自画布以外的其他元素。

检查这一点的最简单方法是将鼠标放在画布的左上角(应为(0, 0) 并在单击时注销鼠标位置以查看您的值是否关闭。在右下角应用相同的角落,检查你的画布宽度和高度。我用这种方法解决了一个类似的问题。在我的例子中,(cx, cy)(-10, -10),这足以在光线投射中出现重大错误。

【讨论】:

您好,尼克,感谢您的回复。我最近又遇到了这个问题。我查看了您的解决方案,但是鼠标坐标似乎正确,尽管我认为这仍然是一个很好的答案,因为它确实会影响相交位置。目前,将我的远截头体和纵横比更改为稍高的值似乎可以解决我的问题。 @Loxodromes 很高兴我能提供一些见解,但我必须说你的情况很奇怪。我正在使用 r62,即使使用最小的运行应用程序,短距离(小于 100 个单位)的光线投射也可以非常准确地工作。你的光线投射距离比这大得多吗?您是否已恢复到最小的测试用例?您使用的是移动浏览器还是桌面浏览器? 我现在在桌面浏览器上运行 r67,我确实使用了更大的单位,因为我使用的是英国地理信息(英国国家网格坐标),所以目前可能导致大约 600000问题。感谢完全调整截锥体,FOV 似乎确实解决了这个问题,尽管我不能诚实地告诉你原因。在此之前我确实使用过光线投射器精度,但这似乎也没有效果。【参考方案2】:

奇怪的是,将透视相机附近的参数从 0.1 更改为 1 后问题似乎自行解决了

camera = new THREE.PerspectiveCamera(45, canvaswidth / canvasheight , 0.1, 10000 );

收件人:

camera = new THREE.PerspectiveCamera(45, canvaswidth / canvasheight , 1, 10000 ); 

我仍然不能 100% 确定为什么这可以解决问题,但它似乎已经奏效了。

编辑:将 FOV 从 45 更改为 60 消除了在更改近端相机参数后仍然发生的光线投射中的轻微失真。

【讨论】:

我在这上面花了几个小时,试图弄明白。谢谢!【参考方案3】:

如果您使用 ClientX 和 ClientY,请使用 event.OffsetX 和 event.OffsetY。

【讨论】:

【参考方案4】:

在这方面遇到了很多困难,我仍然不确定为什么会这样,但是 x 和 y 的这种计算对我有用。

let canvas = document.querySelector('canvas');

let x = (event.offsetX / canvas.clientWidth) * 2 - 1;
let y = -(event.offsetY / canvas.clientHeight) * 2 + 1;

【讨论】:

【参考方案5】:

因为我没有使用全屏分辨率作为我的 WebGL 画布的大小,所以我需要做一个替代计算来减去窗口和画布之间的距离,以定义我的鼠标实际悬停的位置..

function onDocumentMouseMove( event ) 
    mouseVector.x = (event.offsetX / (window.innerWidth - 240)) * 2 - 1;
    mouseVector.y = -(event.offsetY / (window.innerHeight - 100)) * 2 + 1;

// when the mouse moves, call the given function
document.addEventListener( 'mousemove', onDocumentMouseMove, false );

一旦我的鼠标坐标根据画布大小正确计算,其中的对象就会更准确地反应。 (此方案不操作相机,只返回鼠标坐标。)

希望这会有所帮助。

【讨论】:

以上是关于Three.js 从鼠标位置投射光线的主要内容,如果未能解决你的问题,请参考以下文章

Three.js 针对特定点的光线投射

Three.js用相机选择对象,没有鼠标

THREE.js 对单个 > 500k 多边形(面)对象的光线投射非常慢,与地球的线相交

为啥我的光线投射会击中错误的对象?

Three.js - 将光线从物体发送到相机

用于在世界中放置对象时的光线投射抖动