简单的 OpenTK 光线投射

Simple OpenTK Raycasting

好吧,我不知道你是否可以完全考虑它的光线投射,但我基本上是想找到我的 2d 网格上的哪个图块正在悬停,以便我可以在那里放置一个对象。

解决方案应该只拾取网格而不是网格上的建筑物。建筑物突出显示将基于建筑物占据的任何图块是否悬停在上方。

我正在努力实现的一个很好的例子是类似异星工厂的构建系统。

编辑: 网格是一个包含所有图块信息的二维数组。世界中的瓷砖都是 2 个三角形(由顶点数组和索引数组组成)。相机是透视相机(如果 Factorio 使用 Orthographic,如果它使事情更简单,我可以切换到它)。

编辑 2: 该数组包含一个名为 TileInformation 的 class,它有一些与图块包含的内容等相关的内容。瓷砖的大小为 1x1,阵列为 256x256。 (会有多个网格块,可以单独更新。)所有瓦片都在一个网格中,位置以int表示(坐标系为正负。)

你的问题还是不够明确,不过我会做一些假设,希望能符合你的情况。

首先,我们需要一个在 3D 中表示 2D 鼠标位置的拾取射线 space。为此,我们首先将鼠标位置从像素坐标转换为 -1 和 1 之间的归一化设备坐标:

mouseNDCX = 2 * mousePixelX / viewportWidth - 1
mouseNDCY = 1 - 2 * mousePixelY / viewportHeight

然后,我们找到射线。为此,我们需要相机的视图投影矩阵。那么:

mouseNear = inverse(viewProjection) * (mouseNDCX, mouseNDCY, 0, 1)
mouseFar  = inverse(viewProjection) * (mouseNDCX, mouseNDCY, 1, 1)

这将为您提供拾取射线上的两个位置。一个在 z-near 平面上,一个在 z-far 平面上。不要忘记做透视划分:

mouseNear = (1 / mouseNear.w) * mouseNear
mouseFar = (1 / mouseFar.w) * mouseFar

下一步是计算与网格的交点。这是您的问题严重不足的地方。我假设网格位于平行于主平面之一的平面上。在下文中,这将是 xy 平面。如果您有不同的平面,则需要更换相应的组件。我将进一步假设网格位于高度 z.

现在,我们要找到交集,即:

          ((1 - t) * mouseNear + t * mouseFar).z = z
<=> mouseNear.z + t * (mouseFar.z - mouseNear.z) = z
<=>                                            t = (z - mouseNear.z) / (mouseFar.z - mouseNear.z)

这让我们计算交点:

intersection = (1 - t) * mouseNear + t * mouseFar

这个交点位于网格的平面上。最后,我们需要找到瓦片索引。为此,我们只需要考虑 x 和 y 分量。假设您的网格原点位于 o 并且图块的大小为 s,则图块索引为:

i = floor((intersection.x - o.x) / s)
j = floor((intersection.y - o.y) / s)