Как правильно получить высоту местности в точке (x, z) на масштабированной местности

Чтобы правильно сопоставить каждый пиксель изображения карты высот с ландшафтом, мы получим ландшафт как по ширине, так и по длине на 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
}

Когда я рисую ландшафт, я использую stepWidth и stepLength для соответствующего масштабирования ландшафта. Ландшафт будет масштабирован, но будет использоваться только 1023 квадрацикла, всегда 1023, не более (что нормально). Теперь предположим, что я перемещаю своего игрового персонажа, и мне нужно получить высоту местности в текущей позиции игрока. У меня есть функция, которая принимает координаты x и z позиции игрока и возвращает высоту в этой точке. Но поскольку размер ландшафта масштабируется, я не могу просто использовать x и z, переданные функции, мне нужно вычислить правильные, например:

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

После этого мне просто нужно найти 4 соседние вершины новых x и z и выполнить билинейную интерполяцию по всем высотам вершин, чтобы вычислить правильную высоту в позиции игрока.

Все работает нормально. Ландшафт прорисован правильно, и все высоты рассчитаны правильно. Моя проблема заключается в том, что я пытаюсь обойти «ограничение», описанное в начале этого вопроса.

Чтобы обойти проблему, я меняю свою функцию масштабирования на это:

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 (размер местности). Пока все хорошо, местность прорисована именно так, как я ожидал.

Настоящая проблема - это вычисление высоты. Я пробовал много вещей, но просто не могу понять уравнение для вычисления правильных x и z, которые будут использоваться в функции, возвращающей высоту, с учетом нового вычисления шага выше. Погружение x и z с размером шага, как я делал раньше, просто не поможет. Шаг теперь рассчитывается немного иначе и не так просто, как раньше.


person rfgamaral    schedule 28.04.2011    source источник
comment
Не пытайтесь представить выборку карты высот как пиксели, а просто как точки выборки. У вас есть n × m точек выборки ландшафта в любом направлении, и это то, что вы рисуете - или вы можете рассматривать точки выборки как среднее значение каждой ячейки ландшафта, а высота вершин на самом деле является средним значением ячеек, которые они разделяют ( Таким образом, размеры вашей карты высот точно соответствуют количеству ячеек местности). Лично я предпочитаю более поздний метод, и я не рисую местность как квадраты, но в каждой ячейке сэмпла размещаю среднюю вершину, а вокруг нее веер треугольника к средним вершинам.   -  person datenwolf    schedule 29.04.2011


Ответы (2)


Если вы хотите перейти от 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);

}
person corsiKa    schedule 28.04.2011
comment
Не думаю, что вы поняли мой вопрос ... Все это у меня уже есть. Проблема в факторном расчете. Но это не имеет никакого отношения к масштабу 2000 года, это был всего лишь пример. - person rfgamaral; 28.04.2011
comment
@Nazgulled, тогда в чем именно заключается ваш вопрос? Похоже, вам сложно рассчитать высоту на масштабированной местности. - person corsiKa; 28.04.2011
comment
Нет, проблема не в этом. Пожалуйста, прочтите вопрос еще раз, там все объяснено. - person rfgamaral; 28.04.2011
comment
Проблема не в масштабированном ландшафте как таковом. Я могу масштабировать местность вверх и вниз и правильно рассчитывать высоту в любой точке (как описано в вопросе). Проблема в том, что я меняю способ масштабирования. - person rfgamaral; 28.04.2011
comment
ОК, в чем вопрос ?. У вас есть карта высот, верно? Вы ведь умеете рисовать? Вы можете масштабировать его до любого количества точек, верно? Но тогда вы не знаете, как масштабировать высоту? Не масштабируйте это! Определите старые координаты новой точки и проверьте, какую высоту она будет иметь в старых координатах. Поэтому вместо увеличения высоты просто вернитесь к исходному масштабу. - person przemo_li; 12.08.2011

Методы слишком упрощены. А как насчет сложной трехмерной местности со зданиями и объектами? Я использовал glReadPixels для чтения буфера глубины и использовал простую математику, чтобы найти высоту над ландшафтом в любом месте сцены.

person Jim    schedule 24.04.2014