Коли мені знадобилася оцінка кривизни сітки для шейдера шкіри, алгоритм, на якому я закінчився, був такий:
По-перше, я обчислив скалярну кривизну для кожного краю в сітці. Якщо край має положення і нормалі , то його кривизна я оцінила як:n 1 , n 2p1, стор2н1, н2
curvature=(n2−n1)⋅(p2−p1)|p2−p1|2
При цьому обчислюється різниця нормалей, що проектується по краю, як частка довжини ребра. (Дивіться нижче, як я придумав цю формулу.)
Потім для кожної вершини я дивився на викривлення всіх ребер, що торкаються її. У моєму випадку я просто хотів скалярну оцінку "середньої кривизни", тому я в кінцевому підсумку взяв середнє геометричне значення абсолютних значень усіх кривих ребер у кожній вершині. У вашому випадку ви можете знайти мінімальну і максимальну кривизни, а ці краї вважати основними напрямками кривизни (можливо, ортонормалізуючи їх з вершиною нормальної). Це трохи грубо, але це може дати вам досить хороший результат для того, що ви хочете зробити.
Мотивація цієї формули - це перегляд того, що відбувається в 2D при застосуванні до кола:
Припустимо, у вас є коло радіуса (тому його кривизна дорівнює ), і у вас є дві точки на колі з їх нормалами . Положення точок, відносно центру кола, будуть і , завдяки властивості, яку нормалі кола або сфери завжди вказують безпосередньо від її центру.1 / r n 1 , n 2 p 1 = r n 1 p 2 = r n 2r1 / рн1, н2p1= r n1p2= r n2
Тому ви можете відновити радіус якабо. Але в цілому позиції вершин не будуть відносно центру кола. Ми можемо обійти це, віднімаючи два:
| р 2 | / | n 2 | p 2 - p 1r = | p1| / | н1|| p2| / | н2|
p2- с1rкривизна = 1r= r n2- р н1= r ( n2- н1)= | p2- с1|| н2- н1|= | н2- н1|| p2- с1|
Результат точний лише для кіл та сфер. Однак ми можемо розширити його, щоб зробити його трохи більш "толерантним" і використовувати його на довільних 3D-сітках, і, здається, він працює досить добре. Ми можемо зробити формулу більш толерантною, спочатку вектор на напрямок краю, . Це дозволяє, щоб ці два вектори не були абсолютно паралельними (як це у випадку кола); ми просто спроектуємо будь-який компонент, який не є паралельним. Це можна зробити, встановивши крапку з нормалізованим ребром вектора:
p 2 - p 1 кривизнан2- н1p2- с1
кривизна= ( n2- н1) ⋅ нормалізувати ( с2- с1)| p2- с1|= ( n2- н1) ⋅ ( с2- с1) / | p2- с1|| p2- с1|= ( n2- н1) ⋅ ( с2- с1)| p2- с1|2
Et voilà, є формула, яка з’явилася вгорі цієї відповіді. До речі, приємною побічною перевагою використання підписаної проекції (крапкового добутку) є те, що формула надає підписану кривизну: позитивна для опуклих, а негативна для увігнутих поверхонь.
Ще один підхід, який я можу уявити, використовуючи, але не намагався, - це оцінити другу фундаментальну форму поверхні в кожній вершині. Це можна зробити, встановивши дотичну основу у вершині, потім перетворивши всі сусідні вершини в цей дотичний простір і використовуючи найменші квадрати для пошуку найкращої матриці 2FF. Тоді основними напрямками кривизни були б власні вектори цієї матриці. Це здається цікавим, оскільки воно може дозволити вам знайти напрямки кривизни, "натякані" на сусідні вершини, без будь-яких ребер, які явно вказують у цих напрямках, але з іншого боку, це набагато більше коду, більше обчислень і, можливо, менш чисельно надійний.
Документ, який застосовує такий підхід, - Русинкевич, "Оцінка кривизн та їх похідних на трикутних сітках" . Він працює, оцінюючи найкращу матрицю 2FF на трикутник, а потім усереднюючи матриці на вершину (подібно до того, як обчислюються гладкі нормали).