如何从鼠标单击坐标获取WebGL 3d空间中的对象

时间:2011-09-09 16:26:20

标签: javascript 3d mouse webgl coordinate

我正在WebGL中构建一个桌面游戏。电路板可以旋转/缩放。我需要一种方法将画布元素(x,y)上的点击转换为3D空间(x,y,z)中的相关点。最终结果是我想知道包含触及最靠近用户的对象的点的(x,y,z)坐标。例如,用户点击一块,你想象一条穿过3D空间的光线穿过这件作品和游戏板,但是我希望这件作品的(x,y,z)坐在它的位置。触摸。

我觉得这一定是一个非常普遍的问题,但我似乎无法在谷歌中找到解决方案。必须有某种方法将3D空间的当前视图投影到2D中,这样您就可以将2D空间中的每个点映射到3D空间中的相关点。我希望用户能够将鼠标悬停在电路板上的空间上,并使光点变色。

4 个答案:

答案 0 :(得分:23)

您正在寻找一个非项目功能,它将屏幕坐标转换为从摄像机位置到3D世界的光线投射。然后,您必须执行光线/三角形相交测试,以找到与光线相交的最接近相机的三角形。

我有一个在jax/camera.js#L568处可用的未投影示例 - 但您仍需要实现光线/三角形交叉。我在jax/triangle.js#L113处实现了该功能。

有一种更简单且(通常)更快的替代方案,称为“拣选”。如果要选择整个对象(例如,棋子),并且不关心鼠标实际点击的位置,请使用此选项。 WebGL的方法是将整个场景呈现为各种蓝色(蓝色是键,而红色和绿色用于场景中对象的唯一ID)到纹理,然后从中回读一个像素那个纹理。将RGB解码为对象的ID将为您提供被单击的对象。我再次实现了这个,它可以在jax/world.js#L82获得。 (另见第146,162,175行。)

这两种方法都有利有弊(讨论过here以及之后的一些评论),您需要找出最符合您需求的方法。对于巨大的场景,拾取速度较慢,但​​纯JS中的未投影速度非常慢(因为JS本身并不是那么快)所以我最好的建议是尝试两者。

仅供参考,您还可以查看GLU项目和取消项目代码,我将代码松散地放在:http://www.opengl.org/wiki/GluProject_and_gluUnProject_code

答案 1 :(得分:2)

我正在研究这个问题 - 我正在采取的方法是

  1. 渲染对象以选择具有唯一颜色的缓冲区
  2. 读取缓冲区像素,映射回拾取的对象
  3. 将拾取的对象渲染为缓冲区,每个像素颜色为Z深度
  4. 的函数
  5. 读取缓冲区像素,映射回Z深度
  6. 我们选择了对象和近似Z的挑选坐标

答案 2 :(得分:2)

这是工作演示

function onMouseUp(event) {

    event.preventDefault();        
    x_pos = (event.clientX / window.innerWidth) * 2 - 1;
    y_pos = -(event.clientY / window.innerHeight) * 2 + 1;
    z_pos = 0.5;

    var vector = new THREE.Vector3( x_pos , y_pos , z_pos );

    var projector = new THREE.Projector();
    projector.unprojectVector(vector, camera);
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
    var intersects = raycaster.intersectObjects(intersectObjects);

    if (intersects.length > 0) {

        xp = intersects[0].point.x.toFixed(2);
        yp = intersects[0].point.y.toFixed(2);
        zp = intersects[0].point.z.toFixed(2);  
        destination = new THREE.Vector3( xp , yp , zp );

        radians =  Math.atan2( ( driller.position.x - xp) , (driller.position.z - zp));
        radians += 90 * (Math.PI / 180);
        console.log(radians);

        var tween = new TWEEN.Tween(driller.rotation).to({ y : radians },200).easing(TWEEN.Easing.Linear.None).start();

    }

weissner-doors.de/drone /

答案 3 :(得分:0)

从其中一个主题中剔除。 不确定(x,y,z)但你可以使用

获得canvas(x,y)
  

getBoundingClientRect()

function getCanvasCoord(){
  var mx = event.clientX;
  var my = event.clientY;
  var canvas = document.getElementById('canvasId');
  var rect = canvas.getBoundingClientRect();// check if your browser supports this
  mx = mx - rect.left;
  my = my - rect.top;
  return {x: mx , y: my};
}