Poy*_*r23 3 javascript mouse coordinates webgl
由于令人惊讶的是几乎没有关于 webGL 的信息(或者我只是不知道如何搜索它),所以我有一个关于如何将鼠标坐标转换为 3D 坐标的问题,以便查看我在屏幕上单击的确切位置。
所以我的情况是,我有一个非常简单的天空盒,相机位于 [0, 0, 0],我可以通过单击和拖动来查看它的周围。我想要做的是能够单击该天空盒上的某个位置,并知道我单击的位置,因为我需要在该位置上放置注释(某些文本或 html 元素)。当我转向另一边时,该 html 元素必须移动并消失。因此,我需要一种方法来单击鼠标并找出我正在单击立方体的哪一侧以及在什么坐标处,以便我可以正确放置注释。
我使用的是普通的 WebGL,我不使用 THREE.js 或类似的东西。由于它只是一个立方体,我只能假设找到交集不会那么困难,并且不需要额外的库。
嗯,你确实是对的,很难找到一个例子
常见的 webgl 着色器使用以下代码进行 3D 项目
gl_Position = matrix * position;
Run Code Online (Sandbox Code Playgroud)
或者
gl_Position = projection * modelView * position;
Run Code Online (Sandbox Code Playgroud)
或者
gl_Position = projection * view * world * position;
Run Code Online (Sandbox Code Playgroud)
基本上都是一样的。他们将position
其乘以一个矩阵以转换为剪辑空间。你需要做相反的事情来走另一条路,在剪辑空间中占据一个位置,然后隐蔽回position
空间,即
inverse (projection * view * world) * clipSpacePosition
Run Code Online (Sandbox Code Playgroud)
因此,使用您的 3D 库并计算您传递给 WebGL 的矩阵的逆矩阵。例如,这里是一些计算矩阵以使用twgl 的数学库绘制内容的代码
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);
Run Code Online (Sandbox Code Playgroud)
对于有效执行此操作的着色器
gl_Position = viewProjection * world * position
Run Code Online (Sandbox Code Playgroud)
所以我们需要逆
const invMat = m4.inverse(m4.multiply(viewProjection, world));
Run Code Online (Sandbox Code Playgroud)
然后我们需要一个剪辑空间射线。我们将从 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
});
Run Code Online (Sandbox Code Playgroud)
start
和end
现在相对于position
(几何体中的数据),因此您现在必须在 JavaScript 中使用一些射线到三角形代码来遍历所有三角形,并查看从开始到结束的射线是否与一个或多个三角形相交。
请注意,如果您想要的只是世界空间中的光线,而不是位置空间,那么您将使用
const invMat = m4.inverse(viewProjection);
Run Code Online (Sandbox Code Playgroud)
gl_Position = matrix * position;
Run Code Online (Sandbox Code Playgroud)
gl_Position = projection * modelView * position;
Run Code Online (Sandbox Code Playgroud)
gl_Position = projection * view * world * position;
Run Code Online (Sandbox Code Playgroud)
至于WebGL信息有一些here