Недурно для datenwolf! Я полностью согласен с его подходом. Добавление векторов нормалей соседних треугольников для каждой вершины, а затем нормализация - путь. Я просто хочу немного подтолкнуть ответ и поближе познакомиться с частным, но довольно распространенным случаем прямоугольной , гладкой сетки, которая имеет константу х / у шаг . Другими словами, прямоугольная x / y сетка с переменной высотой в каждой точке.
Такая сетка создается циклом по x и y и установкой значения для z и может представлять такие вещи, как поверхность холма. Таким образом, каждая точка сетки представлена вектором
P = (x, y, f(x,y))
где f (x, y) - функция, задающая z каждой точки на сетке.
Обычно, чтобы нарисовать такую сетку, мы используем TriangleStrip или TriangleFan, но любой метод должен давать похожую топографию для получающихся треугольников.
|/ |/ |/ |/
...--+----U----UR---+--...
/| /| 2 /| /| Y
/ | / | / | / | ^
| / | / | / | / |
|/ 1 |/ 3 |/ |/ |
...--L----P----R----+--... +-----> X
/| 6 /| 4 /| /|
/ | / | / | / |
| /5 | / | / | /
|/ |/ |/ |/
...--DL---D----+----+--...
/| /| /| /|
Для triangleStrip каждая вершина P = (x0, y0, z0) имеет 6 смежных вершин, обозначаемых
up = (x0 , y0 + ay, Zup)
upright = (x0 + ax, y0 + ay, Zupright)
right = (x0 + ax, y0 , Zright)
down = (x0 , y0 - ay, Zdown)
downleft = (x0 - ax, y0 - ay, Zdownleft)
left = (x0 - ax, y0 , Zleft)
где ax / ay - постоянный шаг сетки на оси x / y соответственно. На квадратной сетке топор = ау.
ax = width / (nColumns - 1)
ay = height / (nRows - 1)
Таким образом, каждая вершина имеет 6 смежных треугольников, каждый со своим собственным вектором нормалей (обозначается от N1 до N6). Их можно рассчитать, используя перекрестное произведение двух векторов, определяющих сторону треугольника, и внимательно следя за порядком, в котором мы делаем перекрестное произведение. Если нормальный вектор указывает в направлении Z к вам:
N1 = up x left =
= (Yup*Zleft - Yleft*Zup, Xleft*Zup - Xup*ZLeft, Xleft*Yup - Yleft*Xup)
=( (y0 + ay)*Zleft - y0*Zup,
(x0 - ax)*Zup - x0*Zleft,
x0*y0 - (y0 + ay)*(x0 - ax) )
N2 = upright x up
N3 = right x upright
N4 = down x right
N5 = downleft x down
N6 = left x downleft
И результирующий вектор нормали для каждой точки P является суммой от N1 до N6. Нормализуем после суммирования. Очень просто создать цикл, вычислить значения каждого вектора нормалей, добавить их и затем нормализовать. Однако, как указал г-н Шикаданс, это может занять довольно много времени, особенно для больших сеток и / или на встроенных устройствах.
Если мы посмотрим поближе и выполним вычисления вручную, мы обнаружим, что большинство слагаемых взаимно компенсируют друг друга, что дает нам очень элегантное и простое для вычисления окончательное решение для результирующего вектора N. Точка здесь необходимо ускорить вычисления, избегая вычисления координат от N1 до N6, выполняя 6 перекрестных произведений и 6 сложений для каждой точки. Алгебра помогает нам перейти к решению, использовать меньше памяти и меньше процессорного времени.
Я не буду показывать детали вычислений, так как они длинные, но прямолинейные, и я перейду к окончательному выражению вектора Normal для любой точки сетки. Для ясности разложен только N1, остальные векторы выглядят одинаково. После суммирования получаем N, которое еще не нормализовано:
N = N1 + N2 + ... + N6
= .... (long but easy algebra) ...
= ( (2*(Zleft - Zright) - Zupright + Zdownleft + Zup - Zdown) / ax,
(2*(Zdown - Zup) + Zupright + Zdownleft - Zup - Zleft) / ay,
6 )
Вот, пожалуйста! Просто нормализуйте этот вектор, и у вас будет вектор нормали для любой точки сетки, если вы знаете значения Z ее окружающих точек и горизонтальный / вертикальный шаг вашей сетки.
Обратите внимание, что это взвешенное среднее нормальных векторов окружающих треугольников. Вес - это площадь треугольников, и он уже включен в перекрестное произведение.
Вы даже можете упростить его, приняв во внимание только значения Z четырех окружающих точек (вверх, вниз, влево и вправо). В этом случае вы получите:
| \|/ |
N = N1 + N2 + N3 + N4 ..--+----U----+--..
= ( (Zleft - Zright) / ax, | /|\ |
(Zdown - Zup ) / ay, | / | \ |
2 ) \ | / 1|2 \ | /
\|/ | \|/
..--L----P----R--...
/|\ | /|\
/ | \ 4|3 / | \
| \ | / |
| \|/ |
..--+----D----+--..
| /|\ |
, что еще более элегантно и еще быстрее вычислить.
Надеюсь, это сделает несколько мешей быстрее.
Приветствия