Как я могу нарисовать контуры вокруг 3D-моделей? Я имею в виду что-то вроде эффектов в недавней игре про покемонов, которые кажутся однопиксельными очертаниями вокруг них:
3d
shaders
graphics
graphics-programming
мистический портал
источник
источник
Ответы:
Я не думаю, что какие-либо другие ответы здесь достигнут эффекта в Pokémon X / Y. Я не знаю точно, как это делается, но я придумал способ, который в значительной степени похож на то, что они делают в игре.
В Pokémon X / Y контуры рисуются как по краям силуэта, так и по другим не-силуэтным краям (например, там, где уши Райчу встречаются с его головой на следующем скриншоте).
Глядя на сетку Райчу в Blender, вы видите, что ухо (выделено оранжевым цветом выше) - это просто отдельный, не связанный объект, который пересекает голову, создавая резкое изменение нормалей поверхности.
Исходя из этого, я попытался сгенерировать контур на основе нормалей, который требует рендеринга в два прохода:
Первый проход : визуализируйте модель (текстурированную и cel-shaded) без контуров и визуализируйте нормали пространства камеры для второй цели рендеринга.
Второй проход : Сделайте полноэкранный фильтр обнаружения края по нормали с первого прохода.
Первые два изображения ниже показывают результаты первого прохода. Третий план - сам по себе, а последний - окончательный объединенный результат.
Вот фрагментный шейдер OpenGL, который я использовал для обнаружения края во втором проходе. Это лучшее, что я смог придумать, но может быть, есть и лучший способ. Это, вероятно, тоже не очень хорошо оптимизировано.
И перед рендерингом первого прохода я очищаю цель рендеринга нормали от вектора, обращенного от камеры:
Я где-то читал (я добавлю ссылку в комментариях), что Nintendo 3DS использует конвейер с фиксированной функцией вместо шейдеров, так что я думаю, что это не может быть так, как в игре, но сейчас я Я убежден, что мой метод достаточно близок.
источник
Этот эффект особенно распространен в играх, в которых используются эффекты затенения cel, но на самом деле он может применяться независимо от стиля затенения cel.
То, что вы описываете, называется «рендеринг края элемента» и представляет собой процесс выделения различных контуров и контуров модели. Есть много доступных методик и много статей на эту тему.
Простая техника - визуализировать только край силуэта, самый внешний контур. Это можно сделать так же просто, как рендеринг исходной модели с записью трафарета, а затем рендеринг ее снова в режиме толстого каркаса, только там, где значение трафарета отсутствует. Смотрите здесь для примера реализации.
Это не будет выделять внутренний контур и сгибы краев, хотя (как показано на ваших фотографиях). Как правило, чтобы сделать это эффективно, вам нужно извлечь информацию о ребрах сетки (на основе разрывов в нормали граней по обе стороны ребра и построить структуру данных, представляющую каждое ребро).
Затем вы можете написать шейдеры для выдавливания или иным образом визуализировать эти ребра как обычную геометрию поверх базовой модели (или в сочетании с ней). Положение ребра и нормали смежных граней относительно вектора вида используются для определения возможности рисования конкретного ребра.
Вы можете найти дальнейшее обсуждение, детали и документы с различными примерами в Интернете. Например:
источник
dz/dx
и / илиdz/dy
Самый простой способ сделать это, распространенный на старом оборудовании до пиксельных / фрагментных шейдеров и все еще используемый на мобильных устройствах, - это продублировать модель, изменить порядок намотки вершин так, чтобы модель отображалась наизнанку (или, если хотите, вы можете сделайте это в своем инструменте создания 3D-активов, скажем, Blender, переворачивая нормали поверхности - то же самое), затем слегка растяните весь дубликат вокруг его центра, и, наконец, раскрасьте / дублируйте текстуру этого дубликата полностью черным. Это приводит к контурам вокруг вашей исходной модели, если это простая модель, такая как куб. Для более сложных моделей с вогнутыми формами (например, на изображении ниже) необходимо вручную настроить дубликат модели, чтобы она была несколько «толще», чем ее исходный аналог, например сумма Минковского.в 3D. Вы можете начать с выталкивания каждой вершины немного вдоль ее нормали, чтобы сформировать контурную сетку, как это делает преобразование Blender Shrink / Fatten.
Экранные пространство / пиксельных подходы , как правило, медленнее и труднее реализовать хорошо , но Ото не удвоит число вершин в вашем мире. Так что, если вы делаете работу с высоким поли, лучше всего выбрать этот подход. Учитывая современные возможности консоли и рабочего стола для обработки геометрии, я бы не стал беспокоиться о коэффициенте 2 вообще . Cartoon-style = low poly наверняка, поэтому дублировать геометрию проще всего.
Вы можете проверить эффект для себя, например, в Blender, не касаясь кода. Контуры должны выглядеть так, как показано на рисунке ниже, обратите внимание, что некоторые из них являются внутренними, например, под мышкой. Более подробно здесь .
,
источник
Для гладких моделей (очень важно) этот эффект довольно прост. В вашем фрагментном / пиксельном шейдере вам понадобится нормаль фрагмента, который затеняется. Если он очень близок к перпендикуляру (
dot(surface_normal,view_vector) <= .01
- вам, возможно, придется поиграть с этим порогом), тогда закрасьте фрагмент черным вместо его обычного цвета.Этот подход "потребляет" немного модели, чтобы сделать схему. Это может или не может быть то, что вы хотите. По картинке покемонов очень сложно сказать, что именно так и делается. Это зависит от того, ожидаете ли вы, что контур будет включен в какой-либо силуэт персонажа, или вы предпочитаете, чтобы контур заключал силуэт (для этого требуется другая техника).
Выделение будет на любой части поверхности, где оно переходит от передней к задней стороне, включая «внутренние края» (например, ноги на зеленом покемоне или его голову - некоторые другие методы не добавят какой-либо контур к этим ).
При таком подходе объекты с жесткими, негладкими краями (например, куб) не будут выделяться в нужных местах. Это означает, что в некоторых случаях этот подход вообще не подходит; Я понятия не имею, все ли модели Pokemon гладкие или нет.
источник
Наиболее распространенный способ, которым я видел это, - это второй проход рендера на вашей модели. По сути, продублируйте его, переверните нормали и вставьте его в вершинный шейдер. В шейдере масштабируйте каждую вершину вдоль ее нормали. В пиксельном / фрагментном шейдере нарисуйте черный. Это даст вам как внешние, так и внутренние контуры, например, вокруг губ, глаз и т. Д. Это на самом деле довольно дешевый колл-розыгрыш, если вообще ничего дешевле, чем пост-обработка линии, в зависимости от количества моделей и их сложности. Guilty Gear Xrd использует этот метод, потому что легко контролировать толщину линии с помощью цвета вершины.
Второй способ выполнения внутренних линий я узнал из той же игры. На вашей УФ-карте выровняйте текстуру вдоль оси u или v, особенно в областях, где вы хотите получить внутреннюю линию. Нарисуйте черную линию вдоль любой оси и переместите свои UV-координаты в или из этой линии, чтобы создать внутреннюю линию.
Посмотрите видео из GDC для лучшего объяснения: https://www.youtube.com/watch?v=yhGjCzxJV3E
источник
Один из способов сделать контур - использовать в наших моделях нормальные векторы. Нормальные векторы - это векторы, которые перпендикулярны их поверхности (направлены в сторону от поверхности). Хитрость в том, чтобы разделить вашу модель персонажа на две части. Вершины, которые обращены к камере, и вершины, которые обращены от камеры. Мы будем называть их FRONT и BACK соответственно.
Для контура мы берем вершины НАЗАД и слегка смещаем их в направлении их нормальных векторов. Думайте об этом, как о том, чтобы сделать часть нашего персонажа, которая смотрит в сторону от камеры, немного толще. После того, как мы это сделаем, мы назначим им цвет по нашему выбору, и у нас будет хороший контур.
Строка 41: настройка «Cull Front» указывает шейдеру выполнять выборку на передних вершинах. Это означает, что мы будем игнорировать все передние вершины в этом проходе. У нас осталась ОБРАТНАЯ сторона, которой мы хотим немного манипулировать.
Строки 51-53: математика движущихся вершин вдоль их нормальных векторов.
Строка 54: установка цвета вершины на наш цвет по выбору, определенный в свойствах шейдеров.
Полезная ссылка: http://wiki.unity3d.com/index.php/Silhouette-Outlined_Diffuse
Обновить
другой пример
источник
Один из замечательных способов сделать это - визуализировать вашу сцену на текстуре Framebuffer , а затем визуализировать эту текстуру, выполняя Sobel Filtering для каждого пикселя, что является простой техникой для обнаружения краев. Таким образом, вы можете не только сделать сцену пикселированной (установив низкое разрешение для текстуры Framebuffer), но и получить доступ к значениям каждого пикселя, чтобы заставить работать Sobel.
источник