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
x
和 y
值(即 clientX
和 clientY
)很可能是关闭的(例如,您可能会得到这些来自画布以外的其他元素。
检查这一点的最简单方法是将鼠标放在画布的左上角(应为(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 从鼠标位置投射光线的主要内容,如果未能解决你的问题,请参考以下文章