Як розрахувати поверхневі норми для генерованої геометрії


12

У мене є клас, який генерує 3D-форму на основі входів з коду виклику. Вхід - такі речі, як довжина, глибина, дуга і т. Д. Мій код ідеально генерує геометрію, однак у мене виникають проблеми при розрахунку нормальних показників поверхні. При освітленні моя форма має дуже химерне забарвлення / текстуру від неправильних нормальних поверхонь, які обчислюються. З усіх моїх досліджень я вважаю, що моя математика є правильною, здається, що з моєю технікою чи методом щось не так.

Як на високому рівні можна програматично обчислити поверхневі норми для сформованої форми? Я використовую Swift / SceneKit на iOS для свого коду, але загальна відповідь чудова.

У мене є два масиви, які представляють мою форму. Один - це масив 3D-точок, який представляє вершини, що складають форму. Інший масив - це перелік індексів першого масиву, які відображають вершини в трикутники. Мені потрібно взяти ці дані та створити 3-й масив, який представляє собою набір поверхневих нормалів, які допомагають у освітленні форми. (див. SCNGeometrySourceSemanticNormalу SceneKit` )

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


Потрібно більше контексту. Ви намагаєтеся обчислити аналітичні норми для параметричної поверхні? Неявна поверхня? Або ви хочете обчислити нормали із загальної сітки трикутника? Або щось інше?
Натан Рід

Дякую, я додав більше деталей. Щоб відповісти на ваше запитання, мені потрібно обчислити нормали із загальної сітки трикутника. Хоча зрозуміло, що сітка відрізняється залежно від входів. Моя форма - це 3D стрілка, як приклад ось скріншот 2 різних форм (тобто радіальної та лінійної). Клас змінює ширину, глибину, довжину, дугу та радіус сітки за запитом. cl.ly/image/3O0P3X3N3d1d Ви можете бачити дивне освітлення, яке я отримую з моїх поганих спроб вирішити це.
macinjosh

3
Коротка версія: обчислити кожну вершину нормально як нормовану суму нормалей усіх трикутників, які торкаються її. Однак це зробить все гладким, що може не бути тим, що ви хочете для цієї форми. Я спробую пізніше розгорнутись на повну відповідь.
Натан Рід

Гладко - це те, за що я йду!
macinjosh

4
У більшості випадків, якщо розраховувати положення вершин аналітично, ви також можете обчислити норми аналітично. Для параметричної поверхні нормали є поперечним добутком двох градієнтних векторів. Обчислення середнього значення норм трикутника - лише наближення і часто призводить до візуально набагато гіршої якості. Я б опублікував відповідь, але я вже розмістив докладний приклад на SO ( stackoverflow.com/questions/27233820/… ), і я не впевнений, чи хочемо ми тут реплікувати вміст.
Рето Коради

Відповіді:


10

Ви просто не хочете повністю плавних результатів. Хоча коментований метод Натана Ріда: "Обчисліть кожну вершину, щоб відповідати нормальним, підсумовувати їх, нормалізувати суму", як правило, це працює іноді видовищно. Але це не має ніякого значення, ми можемо використовувати цей метод, додавши до нього пункт про відмову.

У цьому випадку ви просто хочете, щоб певні деталі не згладжувались певними іншими частинами. Ви хочете вибіркові жорсткі краї. Так, наприклад, плоскі верх і низ є окремими, утворюючи трикутну смужку збоку, як і кожна плоска область.

Зображення ми після

Зображення 1 : бажаний результат.

Насправді ви хочете лише середні вершини вигнутої області, всі інші можуть використовувати нормальну форму, яку вони утворюють самостійно. Тож вам краще думати про сітку як 9 окремих регіонів, які обробляються без інших.

Показано сітку та нормали]

Зображення 2 : Зображення, що показує структуру сітки та нормали.

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

For vertex in faceVertex:
    normal = vertex.normal
    For adjVertex in adjacentVertices:
        if anglebetween(vertex.normal, adjVertex.normal )  < treshold:
            normal += adjVertex.normal
    normal = normalize(normal)

Це працює, але ви можете просто уникнути всього цього під час створення, оскільки розумієте, що окремі літаки працюють по-різному. Тож лише зігнуті сторони потребують нормального напрямку злиття. Насправді ви можете просто прямо визначити їх від основної математичної форми.


10

Я бачу в основному три способи обчислення нормалей для створеної форми.

Аналітичні норми

У деяких випадках у вас є достатня інформація про поверхню, щоб створити нормали. Наприклад, норма для будь-якої точки на кулі є тривіальною для обчислення. Простіше кажучи, коли ви знаєте похідну функції, ви також знаєте нормальну.

Якщо ваш випадок досить вузький, щоб ви могли використовувати аналітичні норми, вони, ймовірно, дадуть найкращий результат з точки зору точності. Хоча ця методика не надто добре розширюється: якщо вам також потрібно обробляти випадки, коли ви не можете використовувати аналітичні норми, може бути простіше дотримати техніку, яка обробляє загальний випадок, і взагалі скинути аналітичну.

Нормальні вершини

Поперечний добуток двох векторів дає вектор, перпендикулярний до площини, до якої вони належать. Тож отримання норми трикутника просто:

vec3 computeNormal(vec3 a, vec3 b, vec3 c)
{
    return normalize(crossProduct(b - a, c - a));
}

Більше того, у наведеному прикладі довжина поперечного виробу пропорційна площі всередині абс . Таким чином, згладжене нормальне у вершині, поділеній кількома трикутниками, можна обчислити шляхом підсумовування поперечних добутків і нормалізації як останнього кроку, таким чином зважуючи кожен трикутник за його площею.

vec3 computeNormal(vertex a)
{
    vec3 sum = vec3(0, 0, 0);
    list<vertex> adjacentVertices = getAdjacentVertices(a);
    for (int i = 1; i < adjacentVertices; ++i)
    {
        vec3 b = adjacentVertices[i - 1];
        vec3 c = adjacentVertices[i];
        sum += crossProduct(b - a, c - a);
    }
    if (norm(sum) == 0)
    {
        // Degenerate case
        return sum;
    }
    return normalize(sum);
}

Якщо ви працюєте з квадратиками, ви можете скористатись приємним трюком: для quad abcd використовуйте, crossProduct(c - a, d - b)і він буде непогано обробляти випадки, коли квадратик насправді є трикутником.

Іньіго Квілез написав кілька коротких статей на тему: розумна нормалізація сітки та нормальність та площа російських однобічних багатокутників .

Нормативи від часткових похідних

Нормали можуть бути обчислені у фрагменті шейдера з часткових похідних. Математика поза однакова, за винятком цього разу це робиться в просторі екрану. У цій статті Анджело Пессе описана методика: Нормальні норми .


1
Є четвертий спосіб, артист поставив
нормали

@joojaa: Я припускаю, що ви посилаєтесь на звичайні карти? Я ніколи не чув про ручні авторські нормали в іншому випадку.
Жюльєн Герто

1
Ні, нормально написані вручну. Іноді трапляється, що твій художник знає більше про те, як повинні поводитися нормали, ніж це роблять моделі програмістів. Іноді буває мало проблематично для двигунів обчислення, якщо вони припускають, що нормали походять від базових обчислень. Але, безумовно, це відбувається, і ви економите багато часу на математичному моделюванні.
joojaa

1
Їх іноді називають "явними нормалами" (3ds max та терміналогія майя).
Душан Босняк 'пагорб'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.