Обводка в Unity 5


Чтобы посмотреть этот PDF файл с форматированием и разметкой, скачайте его и откройте на своем компьютере.
Рисование обводки вокруг трехмерных
объектов в
Unity

5.6


Постановка задачи

Цель: выделение трехмерного объект на сцене путем обводки контура этого объекта
полупрозрачной линией на экране.
При
этом должна быть предусмотрена

возможность
изменения параметров линии (цвет линии, толщина линии, интенсивность цвета линии и
заполнения и т. д.
),
а
также

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



Рис. 1. Желаемый результат выделения объектов линиями

обводки: объекты могут быть
выделены разными цветами; линии обводки размыты; помимо линий обводки вокруг объекта
сам объект ©затененª цветом линии обводки; интенсивности линий обводки, интенсивности
заполнения ©телаª объекта и прочее настраивается и может

быть анимировано.




Ссылки на источники

Данное ре
шение основано на:

1)
и
нформации из поста
https://forum.unity.com/threads/selection
-
outline.429292/#post
-
2776318
, в котором пользователь с ником ©
Tim
-
C
ª (судя по тегу из команды
Unity Technologies
)
делится исходным кодом шейдера, который используется

для обводки выбранных объектов

в
редакторе
Unity
,

начиная с версии
5.5.



Рис. 2. Обводка в окне редактора
Unity

5.6.
Можно настраивать цвет обводки.

2)
исходном

коде

проекта

Outline

Image

Effect

for

Unity
, выложенном в свободное
пользование

(
MIT License
)

на
github


пользователем
cakeslice

(
https://github.c
om/cakeslice/Outline
-
Effect
).







Описание решения

Возможные подходы к решению

Для решения задачи выделения трехмерных объектов обводкой можно использовать два
принципиально разных подхода:

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

Как правило такой
шейдер реализуется путем смещения вершин в сторону их нормалей, тем самым как бы
©утолщаяª

объекта,
©утолщенныйª объект рендерится в необходимом цвете, а затем объект
рендерится нормально. Такой подход неплохо работает на гладких
объектах, но на угловатых
объектах линия обводки прерывается.

Так же необходимо менять материал объекта, а он может
быть специфическим или меш может состоять из подмеш
ей


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


стандартный рендерер сделает все сам.



Рис
. 3.
Пример использования подхода рисования обводки в шейдере самого объекта.

Второй способ


добавление

линий обводки на этапе пост
-
обработки отрендеренного
кадра.

Такой способ обладает большей гибкостью в плане визуального воплощения, однако,
требует написания большего объема кода

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



Этапы отрисовки линий обводники

Отрисовку линий обводки

на этапе пост
-
обработки

можно разбить

на следующие
ключевые этапы:

1)

Получение маски обводимых объектов:

a.

получение карты г
лубины всего кадра;

b.

рендер обводимых объектов и получение карты глубин обводимых объектов;

c.

обрезка или выделение областей, перекрытых б
лизлежащими к камере
объектами.

2)

Отрисовка обводки:

a.

отрисовка неслаженной линии обводки;

b.

сглаживание линии обводки в гориз
онтальном

(или вертикальном)
направлении;

c.

сглаживание сглаженной в горизонтальном (или вертикальном) направлении в
вертикальном (или горизонтальном, соответственно) направлении.

3)

Наложение обводки на исходное изображение:

a.

получение изображения
линий обводки

и заполнения с учетом настроек
интенсивности и цвета;

b.

наложений линий обводки и заполнения на изображение исходного кадра.


Подробнее о каждом из этапов

отрисовки
.

Далее приведены
изображения,

получаемые на каждом из этапов обработки кадра в
процессе рисования линий обводки.

Положение камеры статической и все изображения
получены под одним и тем же ракурсом.



Рис. 4. Тестовой сцена. Вид с основной камеры.


Рис.
5
.
Карта глубины основной камеры. Слева
D
3
D
9,
справа
D
3
D
11
.

Здесь стоит обратить внимание на то, что помимо цветового окраса (
Direct
3
D

11
использует только красный канал для сохранения глубины)
Direct
3
D

11 инвертирует ось
Z

при
построении карты глубины, т.е.
в
Direct
3
D

9
ближние пиксели темнее чем дальние, а в
Direct
3
D



наоборот.

Это нужно учитывать при нахождении перекрываемых объектов.

Поскольку большинство

современных компьютеров на
Windows

поддерживают

DirectX

11
, шейдер
изначально написан для работы с
D
3
D
11, а при работе
с

D
3
D
9
оси
инвертируются
, и для сравнения дальности пикселя используется только красный канал
.



Рис. 6
. Карта глубины основ
н
ой камеры: слева


исходное изображение, справа


инвертированная глубина.

Так же нужно понимать, что шейдер ра
ботает с нормализированными значениями, т.е.
цвет в канале задается значением от 0 до 1 (где 0


это нет цвета в канале, 1


максимальный цвет
в канале), тоже относится и к размерам экрана (текстуры) и к глубине.

Поскольку камера значение глубины нормализи
ровано, а фактическое расстояния
задается плоскостями

отсечения

(
clipping planes
)


как правило ближняя плоскость 0.03…0.3, а
дальняя 100…3000 условных единиц расстояния (в
Unity

соразмерно метрам), то близ
расположенные объект практически не различимы при

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







Рис.
7
. Рендер обводимых объектов

(сверху при обводке всех кубов, снизу при обводки
дальнего куба)
: слев
а


рендер в белый цвет, по середине


карта глубины в
D
3
D
9
(
инвертированная), справа


карта глубины в
D
3
D
11.

Далее производится сравнение пикселей двух текстур. В зависимости от режима
отсечения перекрытых зон объекта выбирается цвет пикселя. На момент написания статьи
существует 3 режима отсечения перекрытых зон:

1)

Полное отсечение перекрытых зон (
Always

Cut
)


в

этом случае перекрытые пиксели
исключаю
тся из маски линий обводки.

2)

Смешивание (
Mixing
)


в
этом случае в красный канал перекрытого пикселя
записывается интенсивность заполнения перекрытых зон из настроек;

3)

Полная отрисовка объекта (
Draw

Full
)


в этом случ
ае маска линий обводки не
модифицируется.


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




Рис. 8. Получение изображения, вокруг которого будет рисоваться
линия обводки (маска
объектов обводки) при обводке всех кубов: слева


в режиме скрытия перекрытых (невидимых)
участков объекта, справа


в режиме смешанного выделения перек
рытых участков объекта
.



Рис.
9
. Получение изображения, вокруг которого будет ри
соваться линия обводки (маска
объектов обводки)

при обводке только дальнего куба
: слева


в режиме скрытия перекрытых
(невидимых) участков объекта, справа


в режиме смешанног
о выделения перекрытых участков
объекта.



Рис. 10. Линия обводки вокруг маски

при обводке всех кубов
. Толщина линии


1 пиксель
экрана. Слева


в режиме скрытия перекрытых (невидимых) участков объекта, справа


в
режиме смешанного выделения перекрытых участков объекта.



Рис.
1
1
.
Линия обводки вокруг маски

при обводке только дальнего куба
. Толщина линии


1
пиксель
. Слева


в режиме скрытия перекрытых (невидимых) участков объекта, справа


в
режиме смешанного выделе
ния перекрытых участков объекта
.


Рис.
12
. Размытие линии обводки в горизонтальном направлен
ии.


Рис.
13
. Размытие линии обводки в вертикальном направлении.

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

Последоват
ельность в данном случае не критична, и при желании можно сначала размыть
линию во вертикали, а затем по горизонтали


результат будет аналогичным.

Для размытия используются коэффициенты (
Гауссовское ядро

/

Gaussian kernel
):

0.0204001988,

0.0577929595,

0.1215916882,

0.1899858519,

0.2204586031,

0.1899858519,

0.1215916882,

0.0577929595,

0.0204001988


Далее на рассчитывается цвет линии обводки и заполнения с учетом значений
интенсивности линий обводки, заполнения и заполнения перекрытых зон (в режиме смешивания
перекрытых частей обводимого объекта).




Рис.
14
.
Окончательная линия обводки трех
кубов (сверху) и одного куба (снизу) с наложением
на черный фон (слева) и с наложением на исходное изображение (справа) в режиме обрезки
перекрытых частей обводимого объекта.





Рис.
15
.
Окончательная линия обводки трех кубов (сверху) и одного куба (с
низу) с наложением
на черный фон (слева) и с наложением на исходное изображение (справа) в режиме смешивания
перекрытых частей обводимого объекта.





Рис.
16
.
Линии обводки нескольких типов на одном изображении.




Архитектура программной реализации


Рис. 17. Диаграмма классов модуля для отрисовки линий обводки.

На рисунке 17 изображена упрощенная диаграмма классов, используемых для отрисовки
линий обводки. Помимо программного кода ©высокого уровняª, используются кастомные
шейдеры:
OutlineBufferEffect

. и
OutlineEffect
.

OutlineBufferEffect

используется при ренедер
е
обводимых объектов в маску ободки.
OutlineEffect

используется непосредственно в
постобработке.

Основную логику выполняют объекты класса
OutlineEffect
.

Класс
OutlineEffect

является
скриптом поведения (наследуется от
UnityEngine.MonoBehaviour
)
. Объект типа

OutlineEffect

создается, как и любой другой скрипт поведения в
Unity
, путем добавления его в качестве
компонента к игровому объекту (
GameObject
) на сцене. Скрипт
UnityEngine.MonoBehaviour

должен
быть добавлен на объект содержащий компонент

Camera
.


Рис. 18.
Инспектор игрового объекта в
Unity
.

Игровой объект содержит
ком
понент
Camera

и
Outline

Effect
.

Сам
OutlineEffect

не содержит настроек обводки. Единственным доступным для
редактирования полем является ссылка на объект типа
OutlineSettingsGroup
.
Объекты
OutlineSettingsGroup

содержат массив настроек обводки (объекты типа
OutlineTypeSettings
).

Классы

OutlineSettingsGroup

и
OutlineTypeSettings

наследуются от
UnityEngine.ScriptableObject



это

значит, что объекты этих типов
не являются объектами

сцены
,
а
существуют
как физи
ческие данные на жестком диске.


OutlineEffect

(
is
MonoBehaviour
)

OutlineDrawer

OutlineTypeSettings

OutlineSettingsGroup

(is
ScriptableObject
)

OutlineAnimator



Рис. 19. Инспектор типов обводки: слева


обводка при наведении мыши;

справа


обводка при выделении кликом на объект.



Рис. 20
.
Слева


группа настроек, справа


аниматор
.

OutlineTypeSettings

предоставляет следующие настройки:



Name



идентификатор типа обводки (имя файла)
;



Color



цвет линий ободки и заполнения
;






толщина линии обводки
;



LineIntensity



интенсивность

обводки
;



FillAmount



интенсивность заполнения видимых зон
;



CutH
idenMode



режим образки перекрытых зон
;



CutHidenAmount



интенсивность заполнения перекрытых зон (только при выборе
режима Смешивание
(Mixing)
);



Animators



массив аниматоров для текущих настроек.


Аниматор


это объект типа производного от
OutlineAnimator
.
Содержит логику изменения
открытых параметров объекта
OutlineTypeSettings
. В примере используется
BlinkingOutlineAnimator
,

который изменяет значение интенсивности по кривой в указанных
пределах.






Класс
OutlineEffect

содержит вложенный класс
OutlineDrawer
. На этапе инициализации
для каждого типа обводки создается объект типа и связывается. Каждый объекта типа
связывается с одним из типов обводок и отвечает за рендер обводки именно этого типа. Класс
OutlineDrawer

являет
ся закрытым (
private
) и может использоваться только в теле класса
OutlineEffect
.

Объекты к
ласс
а

OutlineEffect

принимаю
т

сообщения

от

движка

Unity
:
Awake
,
Start
,
Update
,
OnPreRender
,
OnRenderImage
,
OnDestroy
.

Методы
Awake

и
Start

осуществляют все необходимые предустановки: хеширование
свойств материалов, создание материалов, настройка основной камеры, предустановка объектов
типа
OutlineDrawer
, предустановка анимацией.

Метод
OnDestroy

осуществляет освобождение ресурсов: удаление ма
териалов и объектов
типа
OutlineDrawer
.

Метод
Update

обновляет анимации обводок.

Основная логика отрисовки линий обводки выполняется методами
OnPreRender

и
OnRenderImage
. В методе
OnPreRender

осуществляется рендер объектов для обводки в текстуру,
которая и
спользуется далее для создания маски обводки. При этом код самого метода
осуществляет вызов методов объектов типа
OutlineDrawer
, для каждого типа линий, которые
нужно отрисовать на этом кадре.





В методе
OnRenderImage

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

Если на текущем кадре нет обводимых объектов, то исходное изо
бражение просто
копируется в выходное:
Graphics
.Blit(source, destination);
.

Если на текущем кадре присутсвуют
обводимые объекты одного типа, то запускается отрисовка линий этого типа.

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

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

вызовет
ошибку.


Теперь рассмотрим подробнее, что происходит в методе
OutlineDrawer
.RenderOutlines(RenderTexture, RenderTexture)
.

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

Затем обновляются свойства материала отрисовки, т.к.
для всех отриосовщиков объект
OutlineEffect

используется один
экземпляр
материа
л
а
.

Непосредственно перед началом процесса получаются временные текстуры для хранения
промежуточных данных. Для наглядности на каждый этап выделена одна текстура, хотя в
реальности можно ограничится меньшим количеством. По завершению текстуры возвращаются.

Весь процесс
отрисовки обводки
разбит на 5 этапов:

1)

Получение маски

(pass #0)
;

2)

Отрисовка линии обводки начальной толщины

(
pass

#
1
)
;

3)

Размыт
ие линии обводки по горизонтали
(
pass

#
2
)
;

4)

Размытие линии обводки по вертикали

(
pass

#
2
)
;

5)

Финальное см
ешивание полученных изображений
(
pass

#
3
)
.



На

каждом

этапе

вызывается

метод
:

Graphics
.Blit(
source
,
destination
, outlineEffectMaterial,
N
);

г
де

source



входное изображение на данном этапе;

destination



результирующие изображение
;

outlineEffectMaterial



материал, используемый для обработки
;

N



порядковый номер
Pass

а шейдера
;






Описание шейдерной программы

Программная реализация включает
в себя две шейдерные программы:
OutlineBufferEffect
,
OutlineEffect
.

OutlineBufferEffect
, задача которого отрисовать обводимые объекты белым цветом.




Вершинный шейдер

(
vert
)
переводит координаты вершин меша в пространство экрана,
используя встроенную функцию
UnityObjectToClipPos
,
которая выполня
ет все необходимые
ра
счеты
. Ф
рагментный

шейд
ер просто возвращает белый цвет.




OutlineEffect



используется для отрисовки обводки.
OutlineEffect

содержит
шест

проход
ов (
Pass
)



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


Нулевой

проход генерирует маску обводки с учетом режима отрисовки перекрытых зон
обводимых объектов.

Сначала получаются значения глуб
ины текущего пикселя карты глубины
основной камеры и рендера обводимых объектов. Если используется
D
3
D
9

(если ось не
инвертирована),

то значения
инвертируются.
Если пиксель имеет
глубину близкую к нулю, то рисуется
возвращается черный цвет. Далее
пиксель р
енедра обводимых объектов
сравнивается с пикселем карты
основной камеры. Если значение
глубины меньше, то рисуется белы,
иначе рисуется черный или цвет
кодируется интенсивностью
заполнения перекрытых зон, в
зависимости от режима. При этом
значение глубины
основной камеры
сдвигается на небольшое значение (
-

0.0001), т.к. может возникнуть
ситуация
,

когда
две грани разных
объектов расположены на одном
расстоянии от камеры и
перекрываются.



Первый

проход рисует линию обводки начальной толщины. Сначала определ
яется
значение пикселя в текущей координате. Если
значение альфа
-
канала больше 0.95 (т.е.
пиксель принадлежит обводимому объекту), то
возвращается черный цвет.

Далее определяются координаты для
взятия образцов

цвета
: текущая
uv



координата + нормализован
ный размер
пикселя * толщина линии обводки


в каждом
из направлений.

Далее определяется цвет в каждой из
смещенных координат. Если цвет хотя бы
одного пикселя больце 0.95


возвращается
белый цвет, иначе черный.



(
-
_ThicknessX,
+_ThichnessY)

(0, +_ThichnessY)

(+_ThicknessX,
+_ThichnessY)

(
-
_ThicknessX, 0)

UV

(+_ThicknessX, 0)

(
-
_ThicknessX,
-
_ThichnessY)

(0,
-
_ThichnessY)

(+_ThicknessX,
-
_ThichnessY)

Второй проход размывает линии обводки.

Для размытия используются коэффициенты
(
Гауссовское ядро

/

Gaussian kernel
):


В цикле осуществляется ©проходª по
соседним относительно текущего пикселям,
определяется значение цвета пикселя на текущей
итерации и умножается на коэффициент
Гауссовского ядра для текущего шага
(удаленности).

Таким образом пиксель

удаленный от
линии обводки, полученной на предыдущем
проходе, будет иметь меньшую интенсивность
цвета, а пиксель лежащий на линии обводки


максимальную.

Этот пр
оход должен быть вызван два раза. На первом этапе передается текстура с линией
обводки начальн
ой толщины, полученная на предыдущем проходе, и установленным
направлением размытия:
(1, 0, 0, 0)


по горизонтали. На следующем этапе передается текстура
с размытой по горизонтали линией и направлением (0, 1, 0, 0)


по вертикали.



Третий проход окрашива
ет области заполнения и линии обводки и смешивает с входным
кадром из основной камеры.



Последние два прохода присутствуют для демонстрации: рендеринга карты глубины
основной камеры и рендера обводимых объектов.




API

Для использования обводки в проект
е необходимо добавить на основную камеру сцены
компонент
OutlineEffect

и установить необходимые настройки.


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

OutlineEffect
:


public

static

void

Add(
GameObject

go,
string

outlineType);

public

static

void

Add(
GameObject

go,
int

outlineTypeHash);


-

указывают, что объект должен обрисоваться линией обводки. В качестве параметров
передаются сам объект для обрисовки (
GameObject

go
) и
название линии в формате строки (
string

outlineType
) или хешированное название в формате целого числа (
int

outlineTypeHash
).


public

static

void

Remove(
GameObject

go,
string

outlineType);

public

static

void

Remove(
GameObject

go,
int

outlineTypeHash)
;


-

ук
азывают, что объект
больше не должен

обрисоваться линией обводки. В качестве
параметров передаются сам объект для обрисовки (
GameObject

go
) и название линии в формате
строки (
string

outlineType
) или хешированное название в формате целого числа (
int

outlineTypeHash
).


public

static

void

Remove(
string

outlineType);

public

static

void

Remove(
int

outlineTypeHash);


-

указывает, что необходимо перестать обрисовывать все объекты указанным типом
обводки
.


public

static

int

HashOutlineTypeName(
string

outlineTypeName);


-

рассчитывает хешированное название в формате целого числа.




Приложенные файлы

  • pdf 9575317
    Размер файла: 1 MB Загрузок: 0

Добавить комментарий