Сглаживать динамически генерируемую сетку в Unity? - PullRequest
0 голосов
/ 10 мая 2018

Учитывая сетку в Unity & C # (которая сама была создана в реальном времени путем слияния более простых базовых сеток), как мы можем во время выполнения * превратить ее в гладкую, почти как обернутую в ткань версию самого себя?Не совсем выпуклая версия, но более округлая, смягчающая острые края, перекрывающая глубокие зазоры и так далее.Поверхность также в идеале должна выглядеть, когда параметр нормали «угол сглаживания» применяется к импортированным объектам.Спасибо!

enter image description here До и после эскиза

* Настройка сетки производится людьми, и ее особенности заранее неизвестны.Все его основные части формы (до того, как мы их объединяем) известны.Базовые части также могут оставаться незакрытыми, если это помогает решению, и было бы очень здорово, если бы существовало решение во время выполнения, которое бы быстро применило затирающую оболочку даже с базовыми частями, которые меняют свое преобразование с течением времени, но статическим одноразовым преобразованиемтоже было бы неплохо.

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

1 Ответ

0 голосов
/ 10 мая 2018

Есть много способов получить что-то похожее, поэтому вы можете выбрать предпочтительный:

Марширующие кубики

Этот алгоритм прост в использовании, но результат всегда наследует блочный «стиль» его. Если вы хотите именно такой вид, используйте его. Если вам нужно что-то более плавное и / или идеальное с точки зрения пикселей, ищите другие способы.

Маршевые лучи и подписанные функции расстояния

Это довольно интересная техника, которая может дать вам много контроля. Вы можете представлять свои базовые части с помощью простого куба / цилиндра / и т.д. уравнения и смешать их вместе с простой математикой.

Здесь вы можете увидеть несколько примеров: http://iquilezles.org/www/articles/distfunctions/distfunctions.htm

Самое приятное в этом то, что его очень просто настроить, вам даже не нужно объединять базовые части, вы просто отправляете свои данные в средство визуализации. Хуже того, это может усложнить вычисления при рендеринге детали.

Модификации старой школы

Здесь у вас больше всего вариантов, но они также самые сложные. Вы начинаете с базовых частей, которые сами по себе не имеют большого количества данных, поэтому вам, вероятно, следует объединить их в одну сетку с помощью операции CSG Union.

Имея эту сетку, вы можете вычислять соседние данные для ваших примитивов:

  • для каждой вершины найдите треугольники, содержащие ее.
  • для каждой вершины найти ребра, содержащие ее.
  • для каждого ребра найдите треугольники, содержащие его.

и т.д.

С такими данными вы можете делать такие вещи:

  • Найдите и вырежьте острую вершину.
  • Найдите и порежьте какой-нибудь острый край.
  • Переместите вершину, чтобы минимизировать угол между треугольниками / ребрами, которые она создает.

и так далее ...

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

Одна простая вещь, с которой я бы начал:

  • Для каждой вершины найти все вершины, связанные с ней любым ребром.
  • Вычислить среднее положение всех этих вершин.
  • Используйте некоторый альфа-параметр в диапазоне [0,1], чтобы смешать начальное положение вершины с усредненным.
  • Реализовать несколько итераций этого алгоритма и добавить для него параметр.
  • Поэкспериментируйте с альфой и количеством итераций.

Используя этот способ, у вас также есть две разные фазы: вычисление и рендеринг, поэтому выполнение с анимацией может стать слишком медленным, но просто рендеринг меша будет быстрее, чем в подходе Ray Marching.

Надеюсь, это поможет.

EDIT:

К сожалению, у меня никогда не было такой необходимости, поэтому у меня нет примера кода, но здесь у вас есть псевдокод, который может вам помочь:

У вас есть сетка:

Mesh mesh;

Массив соседей вершин:

Для любого индекса вершины N, triNeighbors[N] будет хранить индексы других вершин, связанных ребром

List<HashSet<int>>     triNeighbors = new List<HashSet<int>>();

int[] meshTriangles = mesh.triangles;
// iterate vert indices per triangle and store neighbors
for( int i = 0; i < meshTriangles.Length; i += 3 ) {
    // three indices making a triangle
    int v0 = meshTriangles[i];
    int v1 = meshTriangles[i+1];
    int v2 = meshTriangles[i+2];
    int maxV = Mathf.Max( Mathf.Max( v0, v1 ), v2 );

    while( triNeighbors.Count <= maxV )
        triNeighbors.Add( new HashSet<int>() );

    triNeighbors[v0].Add( v1 );
    triNeighbors[v0].Add( v2 );

    triNeighbors[v1].Add( v0 );
    triNeighbors[v1].Add( v2 );

    triNeighbors[v2].Add( v0 );
    triNeighbors[v2].Add( v1 );
}

Теперь для любой отдельной вершины с индексом N вы можете вычислить ее новую усредненную позицию, например:

int counter = 0;
int N = 0;
Vector3 sum = Vector3.zero;
if( triNeighbors.Count > N && triNeighbors[N] != null )
{
    foreach( int V in triNeighbors[N] ) {
        sum += mesh.vertices[ V ];
        counter++;
    }
    sum /= counter;
}

В этом коде могут быть некоторые ошибки, я только что сделал это, но вы должны понять.

...