Войти
Подсказки

Расчет нормалей вершин по карте высот.

Автор:

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

Здесь, я хочу вам показать пример расчета нормалей, базирующийся исключительно на карте высот (похоже на конвертирование карты высот в карту нормалей). Для расчета нормали в каждой вершине я беру 4 значения (слева, справа, сверху и снизу из текущей карты высот), что дает мне приблизительный наклон по направлениям X и Z. Эти значения являются двумя "2D" нормалями (одна по Х, другая по Z). Теперь, все что мне нужно, это найти 3D вектор, который при проецировании на плоскости X=0, Z=0 дает тот же уклон, что и "2D" нормали, и нормализовать его. Надеюсь, приведенный ниже код, поможет вам лучше понять мою  идею. Этот метод должен работать намного быстрее, чем методы, использующие векторные произведения.

( Нормали, рассчитанные этим методом, не зависимы от триангуляции карты высот, ввиду этого, они могут не быть в точности такими же, как нормали полученные методом усреднения, но на результатах это сказывается не сильно. )

// unsigned char h(x, y) returns the height map value at x, y.
// the map is of size width*height
// Vector3 normal[width*height] will contain the calculated normals.
//
// The height map has x, y axes with (0, 0) being the top left corner of the map.
// The resulting mesh is assumed to be in a left hand system with x right, z into the screen
// and y up (i.e. as in DirectX).
//
// yScale denotes the scale of mapping heights to final y values in model space
// (i.e. a height difference of 1 in the height map results in a height difference
// of yScale in the vertex coordinate).
// xzScale denotes the same for the x, z axes. If you have different scale factors
// for x, z then the formula becomes
// normal[y*width+x].set(-sx*yScale, 2*xScale, xScalesy*xScale*yScale/zScale);

for (unsigned int y = 0; y<height; ++y)
{
    for (unsigned int x = 0; x<width; ++x)
    {
        // The ? : and ifs are necessary for the border cases.

        float sx = h(x<width-1 ? x+1 : x, y) - h(x>0 ? x-1 : x, y);
        if (x == 0 || x == width-1)
            sx *= 2;

        float sy = h(x, y<height-1 ? y+1 : y) - h(x, y>0 ?  y-1 : y);
        if (y == 0 || y == height -1)
            sy *= 2;

        normal[y*width+x].set(-sx*yScale, 2*xzScale, sy*yScale);
        normal[y*width+x].normalize();
    }
}

Перевод Calculating Vertex Normals for Height Maps, by Gottfried Chen, www.flipcode.com

29 августа 2003