- PVSM.RU - https://www.pvsm.ru -

Эксперименты с AR: когда C# встречается с CSS

Эксперименты с AR: когда C# встречается с CSS - 1

Часто при работе над проектом самые большие технические сложности возникают тогда, когда меньше всего этого ожидаешь. В моём случае это произошло, когда я работала с Google Creative Lab над прототипом эксперимента по переносу песни Грейс Вандервол [1] Moonlight [2] в дополненную реальность. Нам понравилась идея окружения зрителя красивым написанным от руки текстом песни, который будет раскрываться и парить в пространстве при движении по нему.

Наш AR-текст песни в реальном мире

Эксперименты с AR: когда C# встречается с CSS - 2

Я была кодером проекта; когда я приступила к прототипу, то мне казалось, что самой сложной частью будет AR. Расположение и сохранение стабильного положения объектов в AR — это задача для огромного объёма сложных вычислений, правда? На самом деле, благодаря ARCore [3], взявшему на себя основные сложности, всё оказалось достаточно тривиальным. Однако с созданием анимированного эффекта рукописного текста в 3D-пространстве всё оказалось не так просто.

В этом посте я расскажу о некоторых хитрых хаках, которые я использовала для решения задачи анимирования нашего двухмерного рукописного текста в 3D-пространстве с помощью компонента Unity LineRenderer [4], обеспечивающего достаточную скорость даже при наличии тысяч точек.

Концепция

Когда мы размышляли о возможных музыкальных экспериментах, которые можно провести в AR, нас заинтриговала популярность видеороликов с текстом [5]. Эти видео с текстом, далёкие от простого караоке-стиля, выглядят потрясающе, а для их производства иногда требуется столько же усилий и эстетических деталей, как и для других музыкальных видео. Возможно, вы видели клип Кэти Перри Roar [6] с эмодзи, или видео Тейлор Свифт в стиле дизайна Сола Басса для песни Look What You Made Me Do [7].

Мы наткнулись на текстовые видео Грейс Вандервол [8] и нам понравился их стиль. В таких видео часто используется её рукописный текст, поэтому мы задались вопросом: сможем ли мы создать видео с рукописным текстом, но при этом встроить его в AR? Что, если песня будет сама писать себя параллельно с пением вокруг зрителя — но не изображениями, а изящными, парящими, похожими на трёхмерные линиями?

Мы мгновенно влюбились в эту концепцию и решили попробовать её реализовать.

Получение точек

Для начала я проанализировала данные, которые будут необходимы нам для имитации эффекта написания текста от руки.

Мы не хотели просто располагать изображения с текстом в сцене — нам нужно было, чтобы текст давал физические ощущения, когда зритель может ходить вокруг него и наблюдать за ним. Если бы мы просто разместили 2D-изображения в 3D-пространстве, то при взгляде сбоку они бы пропадали.

Эксперименты с AR: когда C# встречается с CSS - 3

Слева и справа вверху: PNG-изображение в сцене Unity. Оно выглядит нормально, пока вы не начинаете двигаться вокруг него. Если посмотреть на него сбоку, то оно практически исчезает. Кроме того, если приблизиться к нему, оно может казаться пикселизированным.
Слева и справа внизу: данные 3D-точек, используемые для отрисовки линии в пространстве. При взгляде со стороны они сохраняют ощущение объёма. Мы можем обходить вокруг и проходить сквозь них, и они по-прежнему будут казаться 3D-объектом.

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

Чтобы всё это выглядело как рукописный текст, мне также нужно знать, в каком порядке были отрисованы точки. При письме линии возвращаются назад и пересекают друг друга, поэтому точки слева не обязательно должны появляться раньше, чем точки справа. Но как получить эти упорядоченные данные? Мы не можем извлечь их из пиксельного изображения: разумеется, можно получить значения цветов пикселей в массиве (x,y), но это не скажет нам ничего о том, какая точка должна окрашиваться первой.

Эксперименты с AR: когда C# встречается с CSS - 4

Узрите: графика программистов! Допустим, мы пытаемся отрисовать с помощью данных слово «hello», а пунктирная линия означает точку, до которой мы добрались в текущий момент. Пример слева показывает, что произойдёт, когда мы просто будем считывать данные PNG и отрисовывать цветные пиксели слева раньше, чем справа. Это выглядит очень странно! Вместо этого мы хотим имитировать пример справа, для чего нам требуется порядок, в котором отрисовывались точки.

Однако векторные данные обязаны состоять из данных упорядоченных точек, поэтому мы не можем использовать PNG, зато вполне подойдут данные SVG [9].

Но способен ли на это Unity?

Отрисовка точек

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

Поразмышляв над этим какое-то время, я осознала, что Unity не поддерживает SVG, зато полностью поддерживает загрузку XML через несколько стандартных классов C# (например, XmlDocument [10]). А SVG на самом деле — это всего лишь формат векторных изображений на основе XML. Могу ли я загружать данные SVG, если просто сменю расширение с .svg на .xml?

Как ни удивительно, но ответ оказался положительным!

Поэтому мы создали такой рабочий процесс: наши художники отрисовывали текст как контуры в Illustrator, я упрощала эти контуры до прямых линий, экспортировала эти данные контуров как SVG, преобразовывала их в XML (в буквальном смысле просто меняя расширение файлов с .svg на .xml) и без малейших проблем загружала их в Unity.

Эксперименты с AR: когда C# встречается с CSS - 5

Слева: один из SVG, созданных нашими художниками.
Справа: данные XML. Каждая кривая упрощена до ломаных линий. Исходя из практических и эстетических соображений, мы решили, что все слова текста будут начинать отрисовываться одновременно.

Я сделала это, и с удовольствием увидела, что мы можем запросто загружать данные в Unity и без проблем передавать их в LineRenderer [4]. Более того, поскольку у LineRenderer по умолчанию включен эффект биллборда, он выглядел как линия с 3D-объём. Ура! Рукописный текст в AR! Задача решена, верно? Ну, как сказать…

Реализация анимации рукописного текста

Итак, мне удалось расположить парящий в воздухе рукописный текст, и теперь мне всего лишь («всего лишь») оставалось анимировать его написание.

В первой попытке реализации я взяла LineRenderer и для создания эффекта анимации написала скрипт, постепенно добавляющий точки. Я поразилась, когда увидела, насколько сильно стало тормозить приложение.

Оказывается, добавление точек в LineRenderer в реальном времени — это очень вычислительно затратная операция. Я хотела избежать парсинга сложных контуров SVG, поэтому упростила данные контуров в ломаные линии, но для сохранения кривизны контуров для этого понадобилось гораздо больше точек. У меня были сотни, а иногда и тысячи точек текста, и Unity был не очень доволен тем, что я динамически изменяю данные LineRenderer. Нашей целевой платформой были мобильные устройства, поэтому торможение было ещё серьёзней.

Итак, динамическое добавление точек в LineRenderer реализовать не удастся. Но как добиться эффекта анимации без этого?

Известно, что LineRenderer Unity — неподатливый компонент, и я, разумеется, могла избавиться от всей этой работы, купив сторонний ассет. Но, как и в случае с пакетами ассетов для SVG, многие из них представляли собой сочетание дорогих, переусложнённых или неподходящих для нашей задачи решений. Кроме того, меня, как кодера, заинтриговала эта задача, и я стремилась решить её, просто чтобы получить удовольствие от решения. Мне казалось, что должно найтись простое решение с использованием компонентов, доставшихся мне бесплатно.

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

А именно в CSS.

Анимирование точек

Я вспомнила, что читала об этой проблеме несколько лет назад в блоге Криса Вонга [11], где он подробно рассказывал [12] о своём решении задачи создания NYC Taxis: A Day In The Life [13]. Он анимировал такси, движущиеся по карте Манхэттена, но не знал, как заставить такси оставлять след на карте (в формате SVG).

Однако он обнаружил, что может манипулировать параметром линии stroke-dasharray [14], чтобы заставить этот эффект работать. Этот параметр превращает сплошную линию в пунктирную и по сути управляет длиной пунктирных линий и соответствующих им пробелов. Значение 0 означает, что между пунктирными линиями нет пространства, то есть они выглядят как сплошная линия. Однако если увеличить значение, то линия разобьётся на точки и линии. Благодаря реализации хитрых переходов ему удалось анимировать линию без динамического добавления точек.

Эксперименты с AR: когда C# встречается с CSS - 6

Манипулирование массивом пунктиров позволяет разбить сплошную линию на фрагменты из цветных линий и пробелов. Анимация взята из отличного интерактивного демо Джейка Арчибальда [15].

Кроме stroke-dasharray, кодеры CSS могут также манипулировать смещением контура stroke-dashoffset [16]. По словам Джейка Арчибальда, stroke-dashoffset управляет тем, "где вдоль контура начинается первый «пунктир» пунктирной линии, созданной stroke-dasharray [15]".

Что это значит? Допустим, мы будем изменять stroke-dasharray так, что цветной пунктир и пустое пространство оба растянуты на всю длину линии. При stroke-dashoffset, равном 0, наша линия будет цветной. Но при увеличении смещения мы сдвигаем начало линии всё дальше и дальше по контуру, оставляя за ним пустое пространство. И у нас получается анимированная кривая линия!

Эксперименты с AR: когда C# встречается с CSS - 7

Если увеличить до максимума значение dasharray, то мы можем использовать смещение, чтобы линия выглядела анимированной. Анимация взята из отличного интерактивного демо Джейка Арчибальда [15].

Однако очевидно, что в C# у нас нет stroke-dasharray или stroke-dashoffset. Но мы можем манипулировать тайлингом [17] и смещением [18] материала [19], который используется нашим шейдером [20]. Здесь мы можем применить тот же принцип: если у нас есть текстура, похожая на пунктирную кривую, одна часть которой имеет цвет, а другая прозрачная, то мы можем манипулировать тайлингом и смещением текстуры для плавного перемещения текстуры вдоль линии — то есть выполнять переход от цветной линии к прозрачной совершенно без любых манипуляций с точками!

Эксперименты с AR: когда C# встречается с CSS - 8

Мой материал наполовину имеет цвет (белый), наполовину прозрачен. При ручном изменении смещения кажется, что пишется текст. (В приложении мы манипулируем шейдером с помощью простого вызова SetTextureOffset [18].)

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

Скорость и частота кадров снова взлетели до небес, и нам удалось увидеть, как AR-текст сам плавно и изящно пишет себя в реальном мире.

В реальном мире! Мы начали экспериментировать с z-индексами и текстом на разных слоях, чтобы придать ему большее ощущение нахождения в пространстве

Эксперименты с AR: когда C# встречается с CSS - 9

Надеюсь, вам понравился этот небольшой экскурс в процесс обуздания мной известного своей непреклонностью компонента Unity для реализации красивого и малозатратного эффекта. Хотите посмотреть на другие примеры изучения AR в искусстве, танцах и музыке? Посмотрите видео нашего трио [21]. Другую информацию о наших экспериментах с AR можно найти на нашей платформе Experiments [22]. Здесь [3] вы можете попробовать поработать с ARCore. Удачного линейного интерполирования!

Автор: PatientZero

Источник [23]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/video/276966

Ссылки в тексте:

[1] Грейс Вандервол: https://gracevanderwaal.com/

[2] Moonlight: https://www.youtube.com/watch?v=swTki-Klk3g

[3] ARCore: https://developers.google.com/ar/

[4] LineRenderer: https://docs.unity3d.com/Manual/class-LineRenderer.html

[5] видеороликов с текстом: https://www.buzzfeed.com/reggieugwu/the-10-most-popular-lyric-videos-of-all-time?utm_term=.nxnwamyplq#.dwPAm945vw

[6] Roar: https://www.youtube.com/watch?v=e9SeJIgWRPk

[7] Look What You Made Me Do: https://www.youtube.com/watch?v=3K0RzZGpyds

[8] текстовые видео Грейс Вандервол: https://www.youtube.com/playlist?list=PLQpdIQjmTUwzkAYAz2Tu1Xgb2gxOfl-ng

[9] SVG: https://www.w3.org/Graphics/SVG/

[10] XmlDocument: https://msdn.microsoft.com/en-us/library/system.xml.xmldocument.loadxml%28v=vs.110%29.aspx

[11] блоге Криса Вонга: https://chriswhong.com/

[12] подробно рассказывал: https://chriswhong.com/open-data/taxi-techblog-2-leaflet-d3-and-other-frontend-fun/

[13] NYC Taxis: A Day In The Life: http://chriswhong.github.io/nyctaxi/

[14] stroke-dasharray: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray

[15] отличного интерактивного демо Джейка Арчибальда: https://jakearchibald.com/2013/animated-line-drawing-svg/

[16] stroke-dashoffset: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dashoffset

[17] тайлингом: https://docs.unity3d.com/ScriptReference/Material.SetTextureScale.html

[18] смещением: https://docs.unity3d.com/ScriptReference/Material.SetTextureOffset.html

[19] материала: https://docs.unity3d.com/ScriptReference/Material.html

[20] шейдером: https://docs.unity3d.com/Manual/Shaders.html

[21] видео нашего трио: https://youtu.be/7SwZUNDsWaM

[22] платформе Experiments: https://experiments.withgoogle.com/ar

[23] Источник: https://habrahabr.ru/post/352738/?utm_campaign=352738