首页 > 解决方案 > 简单的 OpenTK 光线投射

问题描述

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

该解决方案应该只拾取电网,而不是电网上的建筑物。建筑物突出显示将基于建筑物占用的任何瓷砖是否被悬停。

我正在努力实现的一个很好的例子是像异星工厂一样的建筑系统。

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

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

标签: c#openglgridopentkraycasting

解决方案


你的问题还不够清楚,但我会做一些假设,希望它们符合你的情况。

首先,我们需要一个代表 3D 空间中 2D 鼠标位置的拾取射线。为此,我们首先将鼠标位置从像素坐标转换为介于 -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 平面。如果您有不同的平面,则需要更换相应的组件。我将进一步假设网格位于 height 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并且图块具有 size s,则图块索引为:

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

推荐阅读