【问题标题】:How to correctly get the terrain height at point (x,z) in a scaled terrain如何正确获取缩放地形中点 (x,z) 的地形高度
【发布时间】:2011-04-28 17:37:23
【问题描述】:

为了将高度图图像的每个像素正确映射到地形,我们最终会得到一个宽度和长度都比高度图的实际宽度和长度少 1 个单位的地形。例如,如果我们有一个只有 2 个像素宽的图像,每个像素将映射到四边形的每个顶点。我们有 2 个像素,但只有 1 个地形单位。

我试图通过缩放地形以填充地形末端的空四边形来“解决”这个问题。但是,当我尝试获取某个 (x,z) 点的地形高度时,这是有问题的。问题并不完全是您将看到的缩放。

首先,让我们看看有效的代码。缩放不考虑丢失的四边形的那个。我有一个 1024x1024 的高度图,它将创建一个 1023x1023 四边形的地形(我实际上使用的是三角形,但用四边形很容易解释)而无需任何缩放。

现在让我们通过将适当的参数传递给以下函数来将地形缩放为 2000x2000:

void Terrain::ScaleDimension(float dimWidth, float dimLength) {
    if(dimWidth <= 0.0f || dimLength <= 0.0f) return;

    stepWidth = dimWidth / width; // 1.953125 = 2000 / 1024
    stepLength = dimLength / length; // 1.953125 = 2000 / 1024
}

当我绘制地形时,我使用stepWidthstepLength 来相应地适当缩放地形。地形将被缩放,但只会使用 1023 个四边形,总是 1023,不再有(这很好)。现在假设我正在移动我的游戏角色,我需要获取当前玩家位置的地形高度。我有一个函数,它将获取玩家位置的xz 坐标并返回该点的高度。但是由于地形维度是缩放的,我不能只使用传递给函数的xz,我需要计算正确的,像这样:

x = x / stepWidth;
z = z / stepLength;

之后,我只需要找到新的xz的4个相邻顶点,并对所有顶点高度进行双线性插值,即可计算出玩家位置上的正确高度。

一切正常。正确绘制了地形并正确计算了所有高度。我的问题是当我试图绕过这个问题开头解释的“限制”时。

为了解决这个问题,我将比例函数更改为:

void Terrain::ScaleDimension(float dimWidth, float dimLength) {
    if(dimWidth <= 0.0f || dimLength <= 0.0f) return;

    stepWidth = dimWidth / (width - 1.0f);
    stepLength = dimLength / (length - 1.0f);
}

假设我的地形大小(我传递给上述比例函数的值)与高度图的大小完全相同,即 1024x1204。这将给我一个1.000977517106549364613880742913 的步骤,这将使 1023 个四边形完全适合从 0 到 1024(地形的大小)。到目前为止一切顺利,地形完全按照我的预期绘制。

真正的问题是计算高度。我已经尝试了很多东西,但我无法计算出正确的公式来计算正确的 xz 以用于返回高度的函数,鉴于上面的新步计算强>。像我以前那样以步长潜水xz 根本不会削减它。现在计算步骤的方式略有不同,不像以前那么简单。

【问题讨论】:

  • 不要试图将高度图的采样视为像素,而应将其视为采样点。您在任一方向都有 n×m 地形样本点,这就是您要绘制的内容 - 或者您可以将样本点视为每个地形单元格的平均值,顶点高度实际上是它们共享的单元格的平均值(这样你的高度图尺寸就是地形单元的数量)。就我个人而言,我更喜欢后一种方法,并且我不会将地形绘制为四边形,而是在每个“单元格”的样本位置处有一个中间顶点,并在其周围有一个三角形扇形到平均顶点。

标签: math opengl height terrain heightmap


【解决方案1】:

如果您想从0..1023 放大到0..1999,您需要沿每个位置进行采样以获得正确的值。

Given:  old        new
       0,0       == 0,0
       0,1023    == 0,1999
       1023,0    == 1999,0
       1023,1023 == 1999,1999

换句话说,四个角保持不变。

现在,您需要计算任何给定点的高度,您可以这样称呼它:

float height = convert(1500,1450,1024,2000);

float convert(int newx, int newy, int origScale, int newScale) {
    float factor = ((float)(origScale)) / (float)(newScale);
    float oldx = newx * factor;
    float oldy = newy * factor;

    int oldxlo = floorInt(oldx); // oldx == 3.4, oldxlo = 3
    int oldxhi = ceilInt(oldx); // oldx == 3.4, oldxhi = 34
    int oldylo = floorInt(oldy); // oldy == 3.4, oldylo = 3
    int oldyhi = ceilInt(oldy); // oldy == 3.4, oldyhi = 34

    float topLeftHeight = getHeight(oldxlo,oldylo);
    float topRightHeight = getHeight(oldxhi,oldylo);
    float botLeftHeight = getHeight(oldxlo,oldyhi);
    float botRightHeight = getHeight(oldxhi,oldyhi);

    // now you have the heights of the four corners of the old grid
    // that surround the new grid. You can use a form of interpolation on this grid,
    // I'm sure you can find one somewhere.

    Point3D topLeft(oldxlo,oldylo,topLeftHeight);
    Point3D topRight(oldxhi,oldylo,topRightHeight);
    Point3D botLeft(oldxlo,oldyhi,botLeftHeight);
    Point3D botRight(oldxhi,oldyhi,botRightHeight);


    // or something
    return bilinearInterpolate(topLeft,topRight,botLeft,botRight,newx,newy);

}

【讨论】:

  • 我不认为你理解我的问题......我已经知道了。问题在于“因子”计算。但它与 2000 的比例无关,这只是一个例子。
  • @Nazgulled 那么你的问题到底是什么?您似乎在计算缩放地形的高度时遇到了困难。
  • 不,我不是,这不是问题所在。请再读一遍问题,那里都有解释。
  • 问题不在于缩放地形本身。我可以上下缩放地形并正确计算任意点的高度(如问题中所述)。问题是当我更改缩放的完成方式
  • 好的,问题是什么?你有高度图吗?你可以画出来,对吧?您可以将其缩放到任意数量的点,对吗?但是你不知道如何缩放高度?不要缩放它!确定新点的旧坐标,并检查它在旧坐标中的高度。所以改为缩放高度,只需回到“原始”比例。
【解决方案2】:

方法过于简单。带有建筑物和物体的复杂 3D 地形呢?我已经使用 glReadPixels 来读取深度缓冲区并使用一些简单的数学运算来找到场景中任何地方的海拔高度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    • 1970-01-01
    相关资源
    最近更新 更多