Як я можу виправити артефакти зігзажування УФ-карти на створеній сітці, яка звужується?


10

Я створюю процедурну сітку на основі кривої, і розмір сітки стає меншим по всій кривій, як ви бачите нижче.

введіть тут опис зображення

І проблема полягає в тому, що УФ стає зигзагоподібним, оскільки розмір змінюється (він прекрасно працює, коли розмір сітки однаковий по всій кривій).

введіть тут опис зображення

 Vertices.Add(R);
 Vertices.Add(L);
 UVs.Add(new Vector2(0f, (float)id / count));
 UVs.Add(new Vector2(1f, (float)id / count));
 start = Vertices.Count - 4;
          Triangles.Add(start + 0);
                 Triangles.Add(start + 2);
                 Triangles.Add(start + 1);
                 Triangles.Add(start + 1);
                 Triangles.Add(start + 2);
                 Triangles.Add(start + 3);

 mesh.vertices = Vertices.ToArray();
         //mesh.normals = normales;
         mesh.uv = UVs.ToArray();
         mesh.triangles = Triangles.ToArray();

Як я можу це виправити?


Що таке idі count? Що робить UVs.ToArray()? Як ви завантажуєте вершини та координати текстури на карту?
користувач1118321

@ user1118321 з контексту id- це індекс поточного відрізка з усіх поперечних смуг уздовж смуги, де їх countусього є. List<T>.ToArray()повертає набраний масив усіх записів у списку (так ось, а Vector2[]). Ці буфери даних стають доступними для системи візуалізації шляхом присвоєння їх Meshекземпляру meshв останні кілька рядків. Але нічого з цього не є особливо цікавою частиною коду: як обираються вершинні точки. Ці деталі було б корисніше подивитися. ;)
DMGregory

Це було моє припущення, але я попросив роз'яснити, бо іноді припущення помилкові. Я щось подібне переглядав у власному коді в минулому, щоб зрозуміти, що countнасправді означають вершини замість полігонів, або навпаки. Просто переконайтесь, що все, що ми думаємо, відбувається насправді.
користувач1118321

Відповіді:


13

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

Справа в афінних перетвореннях полягає в тому, що вони рівномірні у всій своїй області - обертання, переклад, масштаб та перекос, які ми застосовуємо до текстури біля вершини A, це те саме, що ми застосовуємо біля вершини B, в будь-якому одному трикутнику. Рядки, паралельні в одному просторі, будуть відображатися на паралельні лінії в іншому, ніколи не збігаючись / розходячись.

Але поступове звуження, яке ви намагаєтеся застосувати, не є рівномірним - це зіставлення паралельних ліній текстури до збіжних ліній на сітці. Це означає, що масштаб текстури, виміряної по всій смузі, постійно змінюється, коли ми рухаємось по смузі. Це більше, ніж афінні перетворення 2D-ультрафіолетового відображення можуть точно представляти: інтерполяція 2D координат uv між сусідніми вершинами отримає одну послідовну шкалу по всьому краю, навіть діагональний край, який повинен скорочуватися в масштабі, коли рухається вниз по смузі. Саме невідповідність - це те, що створює цей кричущий зигзаг.

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

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

Але є спосіб її обійти. Ми можемо використовувати той же трюк, який використовуємо для 3D-рендерінга, щоб намалювати трапеції в перспективі заданих прямокутних стін та підлог: ми використовуємо проективні координати !

Вдосконалення текстурування: Приклад нормальної афінної текстуризації з артефактами зигзагу

Проективне текстурування: Приклад проективного текстурингу, що виправляє артефакти

Для цього нам потрібно додати третю координату uv (uvw) та змінити наші шейдери.

Враховуючи коефіцієнт масштабу в кожній точці (скажімо, рівну ширині вашої смуги на цьому місці), ви можете побудувати 3D-проективну координату uvw з вашої звичайної 2D uv координати таким чином:

Vector3 uv3 = ((Vector3)uv2) * scale;
uv3.z = scale;

Щоб застосувати ці 3D-координати uvw до вашої сітки, вам потрібно використовувати Mesh.SetUVs перевантаження Vector3 (int канал, Список uvs)

Не забудьте змінити вхідну структуру вашого шейдера, щоб очікувати координати 3D текстури (показано тут, використовуючи шейдер, не освітлений за замовчуванням):

struct appdata
{
    float4 vertex : POSITION;
    float3 uv : TEXCOORD0; // Change float2 to float 3.
};
// Also do this for the uv sent from the vertex shader to the fragment shader.

Вам також потрібно вирізати макрос TRANSFORM_TEX у вершинній шейдері, оскільки він очікує 2D uv:

// o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.uv = v.uv;
// If you define a float4 with the special name _MainTex_ST, 
// you can get the same effect the macro had by doing this:
o.uv.xy = o.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw;

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

float2 uv = i.uv.xy / i.uv.z;

Оскільки ми зробили цю 3D-координату uvw з потрібної 2D координати шляхом множення на одне і те ж число, дві операції скасовуються, і ми повертаємося до початкової бажаної 2D координати, але тепер з нелінійною інтерполяцією між вершинами. : D

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


Привіт, я боровся з тією ж проблемою вже досить давно, і це здається саме тим, що відбувається зі мною. Різниця лише в тому, що я працюю в Threejs, а не в єдності. Нам вдалося вирішити проблему, збільшивши кількість трикутників, але все ж хотілося б спробувати проективну текстуру. Чи маєте ви якесь уявлення, як навіть почати реалізовувати це у Threejs? Дякую!
Dživo Jelić

1
Приблизно так само. Вам потрібна третя текстурна координата для зберігання дільника, після чого ви виконуєте поділ у фрагменті шейдера. Якщо у вас виникли проблеми із застосуванням цього питання до вашої справи, запитання нового питання дозволить вам включити зразок коду, який показує, як ви малюєте свою сітку досі, на чому відповіді можна використовувати.
DMGregory

Чи потрібно мені зберігати дільник як третю координату (і через це змініть структуру та виріжте макрос TRANSFORM_TEX, який я не знаю, як зробити у Threejs) чи можу я просто передати дільник як атрибут вершинного шейдера а потім звідти, як варіювання до фрагменту шейдера, де його можна було б використовувати для поділу?
Dživo Jelić

TRANSFORM_TEX - макрос Unity. У вас цього немає в Three.js, тому нічого вирізати не можна. Поки інтерпольовані координати UV і дільники досягають шейдера фрагмента, це не має особливого значення, як ви їх туди дістали. Чи стикалися ви з будь-якими проблемами, надаючи це як атрибут / різницю дотепер?
DMGregory

Я ще не намагався, оскільки не хотів витрачати час, поки не переконався, що це можливо. Лише останнє запитання, дільник також буде інтерпольований, як тільки він досягне фрагмента шейдера, правильно? Значить, на пікселі між двома вершинами це буде якесь інтерпольоване значення, а не початкове значення? Мені важко обернути голову, чому помножити УФ, а потім розділити це допомагає, але я візьму на те слово і спробую. : little_smiling_face: Дякую вам дуже за допомогу!
Dživo Jelić
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.