Когда мне понадобилась оценка кривизны сетки для шейдера скина, алгоритм, на котором я остановился, был такой:
Сначала я вычислил скалярную кривизну для каждого ребра в сетке. Если ребро имеет позиции и нормали n 1 , n 2 , то я оценил его кривизну как:p1,p2n1,n2
кривизна = (n2-n1) ⋅ (p2-p1)|p2-p1|2
Это вычисляет разницу в нормалях, спроецированных вдоль края, как часть длины края. (Смотрите ниже, как я придумал эту формулу.)
Затем для каждой вершины я посмотрел на кривизну всех ребер, которые касаются ее. В моем случае я просто хотел получить скалярную оценку «средней кривизны», поэтому в итоге я взял среднее геометрическое от абсолютных значений всех кривизны ребер в каждой вершине. В вашем случае вы можете найти минимальную и максимальную кривизну и считать эти ребра основными направлениями кривизны (возможно, ортонормировать их с нормалью вершины). Это немного грубо, но это может дать вам достаточно хороший результат для того, что вы хотите сделать.
Мотивация для этой формулы заключается в том, что происходит в 2D применительно к кругу:
Предположим, у вас есть круг радиуса (поэтому его кривизна равна 1 / r ), и у вас есть две точки на окружности с их нормалями nр1 / р . Положения точек относительно центра окружности будут p 1 = r n 1 и p 2 = r n 2 , благодаря свойству, что нормали окружности или сферы всегда указывают прямо из его центра.N1, н2п1= r n1п2= r n2
Поэтому вы можете восстановить радиус как г = | п1| / | N1|или , Но в общем, положение вершин не будет относительно центра круга. Мы можем обойти это, вычитая два:
p 2 - p 1| п2| / | N2|
п2- р1ркривизна = 1р= r n2- р н1= r ( n2- н1)= | п2- р1|| N2- н1|= | N2- н1|| п2- р1|
Результат точен только для кругов и сфер. Однако мы можем расширить его, чтобы сделать его более «терпимым», и использовать его в произвольных трехмерных сетках, и, похоже, он работает достаточно хорошо. Мы можем сделать формулу более «толерантной», сначала спроецировав вектор на направление ребра, p 2 - p 1 . Это позволяет этим двум векторам быть не совсем параллельными (как в случае круга); мы просто спроецируем любой компонент, который не параллелен. Мы можем сделать это, поставив точки с нормализованным вектором ребра:
кривизнаN2- н1п2- р1
кривизна= ( п2- н1) ⋅ нормализовать ( р2- р1)| п2- р1|= ( п2- н1) ⋅ ( р2- р1) / | п2- р1|| п2- р1|= ( п2- н1) ⋅ ( р2- р1)| п2- р1|2
Et voilà, есть формула, которая появилась в верхней части этого ответа. Кстати, хорошая сторона выгода от использования подписанной проекции (скалярное произведение) является то , что формула затем дает подписанную кривизну: положительная результат на выпуклый, так и отрицательном для вогнутых поверхностей.
Другой подход, который я могу себе представить, используя, но не пытался, это оценить вторую фундаментальную форму поверхности в каждой вершине. Это можно сделать, установив касательный базис в вершине, затем преобразовав все соседние вершины в это касательное пространство и используя метод наименьших квадратов, чтобы найти матрицу 2FF наилучшего соответствия. Тогда основными направлениями кривизны будут собственные векторы этой матрицы. Это кажется интересным, поскольку может позволить вам найти направления кривизны, «подразумеваемые» соседними вершинами без каких-либо ребер, явно указывающих в этих направлениях, но с другой стороны, это намного больше кода, больше вычислений и, возможно, менее численно устойчиво.
Статья, в которой используется такой подход, - Русинкевич, «Оценка кривизны и ее производных на треугольных сетках» . Он работает путем оценки матрицы 2FF наилучшего соответствия на треугольник, а затем усредняет матрицы на вершину (аналогично тому, как вычисляются гладкие нормали).