Если вы рассматриваете каждый пиксель как вершину, а не грань, вы можете создать простую треугольную сетку.
+--+--+
|\ |\ |
| \| \|
+--+--+
|\ |\ |
| \| \|
+--+--+
Каждая вершина имеет координаты x и y, соответствующие x и y изпиксель на карте.Координата z основана на значении на карте в этом месте.Треугольники могут быть сгенерированы явно или неявно по их положению в сетке.
Вам нужен нормальный в каждой вершине .
A вершина нормаль можно вычислить, взяв средневзвешенное по площади значение поверхность нормалей для каждого из треугольников, которые встречаются в этой точке.
Если у вас есть треугольник с вершинами v0
, v1
, v2
, тогда вы можете использовать векторное перекрестное произведение (из двух векторов, которые лежат на двух сторонах треугольника), чтобы вычислить вектор в направлении нормали и масштабировать пропорционально площади треугольника.
Vector3 contribution = Cross(v1 - v0, v2 - v1);
Каждая из ваших вершин, которые не находятся на краю, будет разделена на шесть треугольников.Вы можете перебрать эти треугольники, суммируя contribution
s, а затем нормализовать векторную сумму.
Примечание: Вы должны рассчитать перекрестные произведения согласованным образом, чтобы убедиться, чтонормали все указывают в одном направлении.Всегда выбирайте две стороны в одном и том же порядке (по часовой стрелке или против часовой стрелки).Если вы смешаете некоторые из них, эти вклады будут указывать в противоположном направлении.
Для вершин на краю вы получите более короткий цикл и множество особых случаев.Вероятно, проще создать границу вокруг вашей сетки фальшивых вершин, а затем вычислить нормали для внутренних и отбросить фальшивые границы.
for each interior vertex V {
Vector3 sum(0.0, 0.0, 0.0);
for each of the six triangles T that share V {
const Vector3 side1 = T.v1 - T.v0;
const Vector3 side2 = T.v2 - T.v1;
const Vector3 contribution = Cross(side1, side2);
sum += contribution;
}
sum.Normalize();
V.normal = sum;
}
Если вам нужна нормаль в определенной точке треугольника (кроме одной из вершин), вы можете интерполировать, взвешивая нормали трех вершин по барицентрическим координатам вашей точки.Вот как графические растеризаторы воспринимают обычное для затенения.Это позволяет треугольной сетке выглядеть как гладкая криволинейная поверхность, а не как куча смежных плоских треугольников.
Совет: Для первого теста используйте идеально плоскую сетку и убедитесь, что всевычисленные нормали направлены прямо вверх.