- PVSM.RU - https://www.pvsm.ru -
Часто при работе над проектом самые большие технические сложности возникают тогда, когда меньше всего этого ожидаешь. В моём случае это произошло, когда я работала с Google Creative Lab над прототипом эксперимента по переносу песни Грейс Вандервол [1] Moonlight [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-пространстве, то при взгляде сбоку они бы пропадали.
Слева и справа вверху: PNG-изображение в сцене Unity. Оно выглядит нормально, пока вы не начинаете двигаться вокруг него. Если посмотреть на него сбоку, то оно практически исчезает. Кроме того, если приблизиться к нему, оно может казаться пикселизированным.
Слева и справа внизу: данные 3D-точек, используемые для отрисовки линии в пространстве. При взгляде со стороны они сохраняют ощущение объёма. Мы можем обходить вокруг и проходить сквозь них, и они по-прежнему будут казаться 3D-объектом.
Итак, никаких изображений: мне придётся разбить изображения с рукописным текстом на данные точек, которые можно будет использовать для отрисовки линий.
Чтобы всё это выглядело как рукописный текст, мне также нужно знать, в каком порядке были отрисованы точки. При письме линии возвращаются назад и пересекают друг друга, поэтому точки слева не обязательно должны появляться раньше, чем точки справа. Но как получить эти упорядоченные данные? Мы не можем извлечь их из пиксельного изображения: разумеется, можно получить значения цветов пикселей в массиве (x,y), но это не скажет нам ничего о том, какая точка должна окрашиваться первой.
Узрите: графика программистов! Допустим, мы пытаемся отрисовать с помощью данных слово «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.
Слева: один из 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 означает, что между пунктирными линиями нет пространства, то есть они выглядят как сплошная линия. Однако если увеличить значение, то линия разобьётся на точки и линии. Благодаря реализации хитрых переходов ему удалось анимировать линию без динамического добавления точек.
Манипулирование массивом пунктиров позволяет разбить сплошную линию на фрагменты из цветных линий и пробелов. Анимация взята из отличного интерактивного демо Джейка Арчибальда [15].
Кроме stroke-dasharray, кодеры CSS могут также манипулировать смещением контура stroke-dashoffset [16]. По словам Джейка Арчибальда, stroke-dashoffset управляет тем, "где вдоль контура начинается первый «пунктир» пунктирной линии, созданной stroke-dasharray [15]".
Что это значит? Допустим, мы будем изменять stroke-dasharray так, что цветной пунктир и пустое пространство оба растянуты на всю длину линии. При stroke-dashoffset, равном 0, наша линия будет цветной. Но при увеличении смещения мы сдвигаем начало линии всё дальше и дальше по контуру, оставляя за ним пустое пространство. И у нас получается анимированная кривая линия!
Если увеличить до максимума значение dasharray, то мы можем использовать смещение, чтобы линия выглядела анимированной. Анимация взята из отличного интерактивного демо Джейка Арчибальда [15].
Однако очевидно, что в C# у нас нет stroke-dasharray или stroke-dashoffset. Но мы можем манипулировать тайлингом [17] и смещением [18] материала [19], который используется нашим шейдером [20]. Здесь мы можем применить тот же принцип: если у нас есть текстура, похожая на пунктирную кривую, одна часть которой имеет цвет, а другая прозрачная, то мы можем манипулировать тайлингом и смещением текстуры для плавного перемещения текстуры вдоль линии — то есть выполнять переход от цветной линии к прозрачной совершенно без любых манипуляций с точками!
Мой материал наполовину имеет цвет (белый), наполовину прозрачен. При ручном изменении смещения кажется, что пишется текст. (В приложении мы манипулируем шейдером с помощью простого вызова SetTextureOffset [18].)
Именно так мы и сделали! Зная время создания слова, а также время, за которое оно должно быть написано, я смогла просто линейно проинтерполировать смещение на основании того, насколько мы близко к времени завершения написания. И при этом не требуются манипуляции значениями точек!
Скорость и частота кадров снова взлетели до небес, и нам удалось увидеть, как AR-текст сам плавно и изящно пишет себя в реальном мире.
Надеюсь, вам понравился этот небольшой экскурс в процесс обуздания мной известного своей непреклонностью компонента 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
Нажмите здесь для печати.