获取WebGL中鼠标单击的3D坐标

问题描述 投票:0回答:1

由于令人惊讶的是,几乎没有关于webGL的信息(或者我只是不知道如何搜索),所以我有一个关于如何将鼠标坐标转换为3D坐标的问题,因此想知道我在屏幕上的确切位置点击。

所以我的情况是,我有一个非常简单的天空盒,相机位于[0,0,0],可以通过单击和拖动来环顾四周。我想做的是能够单击该Skybox上的某个位置,并知道要单击的位置,因为我需要在该位置上添加注释(一些文本或html元素)。而且该html元素必须移动,并且在我转向另一侧时不可见。因此,我需要一种方法来单击鼠标,找出我单击的立方体的哪一侧以及在什么坐标处,以便可以正确放置批注。

我使用的是普通的WebGL,我不使用THREE.js或类似的东西。因为它只是一个立方体,所以我只能假设找到相交不会那么困难,也不需要额外的库。

javascript webgl coordinates mouse
1个回答
0
投票

您肯定是对的,很难找到一个例子😭

[一个通用的webgl着色器使用3D或类似代码进行投影]

gl_Position = matrix * position;

gl_Position = projection * modelView * position;

gl_Position = projection * view * world * position;

基本上都是相同的东西。他们取position并将其乘以矩阵以转换为剪辑空间。您需要做相反的操作,否则,在剪辑空间中占据一个位置,然后隐蔽回到position空间,即[>

inverse (projection * view * world) * clipSpacePosition

因此,请使用3D库并计算要传递给WebGL的矩阵的逆。例如,这里是一些代码,这些代码正在计算矩阵以使用twgl's数学库

  const fov = 30 * Math.PI / 180;
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  const zNear = 0.5;
  const zFar = 10;
  const projection = m4.perspective(fov, aspect, zNear, zFar);

  const eye = [1, 4, -6];
  const target = [0, 0, 0];
  const up = [0, 1, 0];
  const camera = m4.lookAt(eye, target, up);

  const view = m4.inverse(camera);
  const viewProjection = m4.multiply(projection, view);
  const world = m4.rotationY(time);

对于有效执行此操作的着色器

  gl_Position = viewProjection * world * position

所以我们需要逆

  const invMat = m4.inverse(m4.multiply(viewProjection, world));

然后我们需要一个剪辑空间射线。我们正在从2D到3D,因此我们将使用-1和+1作为Z值,使光线从zNear到zFar切成平截头体。

  canvas.addEventListener('mousemove', (e) => {
     const rect = canvas.getBoundingClientRect();
     const x = e.clientX - rect.left;
     const y = e.clientY - rect.top;

     const clipX = x / rect.width  *  2 - 1;
     const clipY = y / rect.height * -2 + 1;

     const start = m4.transformPoint(invMat, [clipX, clipY, -1]);
     const end   = m4.transformPoint(invMat, [clipX, clipY,  1]);

     ... do something with start/end
  });

startend现在相对于position(几何图形中的数据),因此您现在必须在JavaScript中使用一些射线到三角代码来遍历所有三角形,并查看射线是否从头到尾结束与一个或多个三角形的相交。

请注意,如果您要的只是世界空间中的光线,而不是位置空间,那么您将使用

  const invMat = m4.inverse(viewProjection);
© www.soinside.com 2019 - 2024. All rights reserved.