Javascript 如何从鼠标单击坐标获取WebGL三维空间中的对象

Javascript 如何从鼠标单击坐标获取WebGL三维空间中的对象,javascript,3d,mouse,webgl,coordinate,Javascript,3d,Mouse,Webgl,Coordinate,我正在WebGL中构建一个棋盘游戏。电路板可以旋转/缩放。我需要一种方法将画布元素x,y上的点击转换为三维空间x,y,z中的相关点。最终的结果是,我想知道x,y,z坐标,其中包含与用户最近的对象接触的点。例如,用户点击一个棋子,你可以想象一条光线穿过3D空间,穿过棋子和游戏板,但我想要棋子的x,y,z坐标在它被触摸的地方 我觉得这一定是一个非常常见的问题,但我似乎无法在我的谷歌中找到解决方案。必须有某种方法将三维空间的当前视图投影到二维,以便可以将二维空间中的每个点映射到三维空间中的相关点。我希

我正在WebGL中构建一个棋盘游戏。电路板可以旋转/缩放。我需要一种方法将画布元素x,y上的点击转换为三维空间x,y,z中的相关点。最终的结果是,我想知道x,y,z坐标,其中包含与用户最近的对象接触的点。例如,用户点击一个棋子,你可以想象一条光线穿过3D空间,穿过棋子和游戏板,但我想要棋子的x,y,z坐标在它被触摸的地方


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

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

我有一个在的未投影示例,但是您仍然需要实现光线/三角形相交。我现在有一个实现

然而,有一种更简单、通常更快的选择,叫做“挑选”。如果要选择整个对象(例如,一个棋子),并且不关心鼠标实际单击的位置,请使用此选项。WebGL实现这一点的方法是以各种深浅的蓝色渲染整个场景。蓝色是一个关键点,而红色和绿色用于将场景中对象的唯一ID转换为纹理,然后从该纹理读回一个像素。将RGB解码为对象的ID将显示单击的对象。同样,我已经实现了这一点,它可以在。另见第146、162、175行

这两种方法都讨论了优缺点,在后面的一些评论中,您需要找出哪种方法最适合您的需要。对于大型场景,拾取速度比较慢,但是在纯JS中取消投影速度非常慢,因为JS本身并没有那么快,所以我最好的建议是对两者都进行实验


仅供参考,您还可以查看GLU项目和非项目代码,我的代码大致基于此:

我目前正在解决这个问题-我采取的方法是

渲染对象以拾取每个具有唯一颜色的缓冲区 读取缓冲区像素,映射回拾取的对象 将拾取的对象渲染到缓冲区,每个像素颜色为Z深度的函数 读取缓冲区像素,映射回Z深度 我们已经拾取了对象,并对拾取坐标进行了近似Z
这是工作演示

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/

从一个线程中提取。 不确定x,y,z,但你可以使用

getBoundingClientRect


你不是在说这个吧?把一条法线从相机镜头放到平面上,算出POI。我想这是我想做的事情的一般描述,但我无法从他的描述中算出一个算法。把视口想象成一个平面,位于0,0,0,矩形的中心在原点,一定会有某种计算。我会仔细考虑一下,我相信有一个优雅的解决方案。澄清一下:在WebGL中挑选通常比不投射快,纯粹是因为JS速度慢,挑选利用GPU进行硬件加速,从而绕过JS瓶颈。在传统的C实现中,取消投影可能是一种方法,特别是当您只需要检查非常少的三角形时。哇,非常感谢,我将研究所有这些。这完美地回答了我的问题。所以,如果我需要知道确切的三角形/垂直度,选择是不够的?正确。您可以通过使用不同的拾取颜色绘制每个三角形来解决这个问题,但这会非常缓慢,我怀疑它在JavaScript中是否可行,但奇怪的事情发生了,因为每个三角形都需要一个新的过程。对于精确的三角形/顶点信息,最好的选择是非投影。只是为了澄清,术语拾取与使用的任何特定技术无关。另外,根据代码的结构,当屏幕上有几千个可见对象时,通过ColorID拾取代码可能会变得非常缓慢。这就是为什么我建议对场景和网格三角形应用适当的空间细分进行光线拾取。
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};
}