Как стать автором
Обновить

Создание панорамных видео в Unity

Время на прочтение9 мин
Количество просмотров5.8K
Автор оригинала: Alan Zucconi

Зачем нужны панорамные видео?


Большинство статей моего блога рассчитано на разработчиков игр. Если вы один из них, то можете задаться вопросом, чем вас может заинтересовать создание панорамных видео (360° videos). Виртуальная реальность — очень успешная отрасль, на различных платформах каждый год выпускается всё больше игр. Многие игроки узнают о VR-играх через трейлеры, которые, к сожалению, записаны в 2D.


Если вы хотите сделать ещё один шаг вперёд, то можете создать дополнительный трейлер в панорамном видео, чтобы продемонстрировать весь потенциал вашей игры. Хотя для игры в VR обычно требуется дорогая гарнитура, панорамные видео нативно поддерживаются YouTube без необходимости дополнительного оборудования. А если у вас есть телефон, то вы можете очень просто превратить его в VR-гарнитуру с помощью Google Cardboard.

Это может обеспечить людям гораздо более сильное погружение и дать почувствовать, в чём смысл вашей игры. Такие фильмы, как «Оно» (см. трейлер ниже) и «Заклятие» полностью воспользовались этим: для них создали VR-игры (с трейлерами в панорамном видео), обеспечившие более интерактивный опыт.


Наконец, панорамные видео отлично подходят для образовательных целей, это можно увидеть на примере All Discovered Exoplanets: A Narrated 360 VR Journey.

Разбираемся с панорамными видео


Скорее всего, вы знакомы с YouTube и с тем, как он работает. Однако панорамные видео знакомы не столь многим. Большинство видео записывается на камеру, фиксирующую только небольшую часть окружения. Панорамные видео же одновременно записывают всё, что происходит во всех направлениях. Обычно для этого требуются специальные камеры, называемые всенаправленными камерами. Они или используют кривые зеркала для отражения окружающего мира в традиционную камеру (почти так же, как объектив «рыбий глаз») или имеют несколько камер, смотрящих в разные направления. Одной из таких камер является GoPro Omni (см. ниже), которая по сути является устройством, содержащим шесть стандартных камер с объективами «рыбий глаз».


Легко понять, почему оборудование, необходимое для записи панорамных видео, обычно более дорогое по сравнению с традиционными камерами. Однако это не единственная причина, ограничивающая их распространение. Для правильного воспроизведения панорамных видео требуется специальное ПО и оборудование. Экраны, как и камеры, предназначены для воссоздания только небольшой части окружений. YouTube смог обойти это ограничение, позволив зрителям «поворачивать» видео, чтобы можно было осматриваться. Если вы смотрите панорамное видео с телефона или планшета, то обычно двигаете его в пространстве, чтобы увидеть разные части «сферы» на 360°.

YouTube поддерживает два типа панорамных видео: моно и стерео (последние часто называют видео в виртуальной реальности). Разница между ними заключается в том, что стереовидео предназначено для VR-гарнитур и может передать ощущение глубины, которое невозможно почувствовать в традиционных видео. Это реализуется наличием не одного, а двух видео, по одному для каждого глаза. Эти два видео одновременно записываются двумя камерами, расстояние между которыми сравнимо с расстоянием между глазами. В результате этого VR-видео могут «обмануть» мозг и он будет воспринимать истинное расстояние, как в повседневной жизни.

В таблице показаны требования, которые имеют эти два типа видео.

Название 360° video Virtual Reality Video
Моно Стерео
2D 3D
Ссылка Поддержка Поддержка
Частота кадров 24, 25, 30, 48, 50, 60 25, 30, 50, 60
Формат Равнопромежуточный
Соотношение сторон 2:1
Выше-ниже равнопромежуточного
Соотношение сторон 1:1
Разрешение Рекомендуемое: 7168 x 3584, до 8192 x 4096 От 5120 x 5120 до 8192 x 8192

Учтите, что YouTube постоянно работает над усовершенствованием поддержки панорамных видео, поэтому в будущем всё может измениться. Прежде чем следовать этим спецификациям, прочитайте информацию по ссылкам из таблицы.

Проецирование видео


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

Существует множество способов преобразования (строго говоря, проецирования) сферы на прямоугольник. Вероятно, наиболее известный — это цилиндрическая проекция, ставшая популярной после того, как картограф Герард Меркатор начал в 1569 году использовать её для преобразования поверхности планеты в плоские карты.

Однако чаще всего в панорамных видео используется равнопромежуточная проекция (см. ниже).


Пространственный звук


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

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

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

  • First-Order Ambisonics
  • First-Order Ambisonics with Head-Locked Stereo

Ambisonics — это формат звука, используемый для записи не только звука, но и направления, из которого он поступает. First-Order Ambisonics (FOA) для кодирования направленности источника звука использует четыре аудиоканала. Чтобы приблизительно понять, как это работает, скажу, что запись звука FOA немного напоминает запись четырьмя микрофонами. Обычно ошибочно представляют, что эти четыре микрофона расположены в кардинальных точках (один перед зрителем, другой позади, третий слева и четвёртый справа). Ambisonics работает не так, но об этом мы сможем поговорить в других постах.

Хоть FOA использует 4 канала, YouTube поддерживает и шестиканальную версию, в которую просто добавлены традиционные левый и правый стереоканалы. Этот формат называется FOA with Head-Locked Stereo.

Особое внимание нужно уделить кодированию панорамного видео (стерео или моно), потому что не все форматы поддерживают 4 или 6 аудиоканалов. YouTube рекомендует следующее:

  • Формат: MP4, MOV
  • Кодек: H.264, ProRes, DNxHR

Если вы работаете в Premiere Pro 2018 или более новой версии, то лучше всего кодировать видео как Quicktime кодеком ProRes. Подробнее о поддерживаемых YouTube форматах пространственного звука можно прочитать здесь.

Как создать панорамное видео в Unity


Одной из множества функций, добавленных в Unity 2018.1, стала возможность делать скриншоты из камеры в формате, совместимом с панорамными видео YouTube. Эта функция вкратце описана в посте на веб-сайте Unity: Stereo 360 Image and Video Capture. К сожалению, в нём нет ссылки на сцену для тестирования.

Теория


Чаще всего ролики по играм записываются во время выполнения игры. Это подходит для стандартных видео, но обычно не подходит для панорамных. Основная причина заключается в том, что для рендеринга панорамной игры требуется гораздо большая площадь, из-за чего частота кадров сильно падает. Более стандартным подходом является рендеринг и экспорт каждого кадра в фоновом режиме, чтобы в дальнейшем их можно было отредактировать в стороннем ПО, например, ffmpeg или Premiere Pro. Именно этим мы и займёмся в нашем туториале.

Рендеринг панорамной сцены в Unity — довольно простой процесс, состоящий из трёх этапов:

  • Рендеринг сцены в текстуру кубической карты (предпочтительный в Unity формат для панорамных текстур)
  • Преобразование кубической карты в равнопромежуточную проекцию (предпочтительный для панорамных видео YouTube формат)
  • Сохранение равнопромежуточной проекции в PNG

Первые два этапа необходимы из-за особенностей работы камер в Unity.

Если вы знакомы с Unity, то, вероятно, знаете, что предпочтительный способ хранения панорамных текстур — это кубическая карта, которая является способом упаковки шести разных изображений без деформаций (см. ниже). Кубические карты часто используются для скайбоксов (skybox) и зондов отражений (reflection probes), поэтому есть вероятность, что вы уже с ними сталкивались.


Чтобы создать панорамную текстуру, Unity рендерит сцену шесть раз, каждый раз под другим углом. Камера поворачивается так, как будто совпадает с одной из шести граней куба. В результате каждый панорамный скриншот является шестью традиционными, соединёнными вместе.

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

Последним этапом будет экспорт равнопромежуточной текстуры в файл PNG. После рендеринга всех кадров видео можно объединить их при помощи программы наподобие ffmpeg или Premiere Pro.

Код


Первым шагом будет создание скрипта (в представленных ниже фрагментах он называется Camera360) и прикрепление его к камере, которая должна выполнять рендеринг. Однако код будет меняться в зависимости от того, хотим ли мы отрендерить видео в моно (360°/mono/2D) или в стерео (VR/stereo/3D).

Моно


Давайте начнём с моноверсии:

public class Camera360 : MonoBehaviour
{
    public Camera Camera;
    
    public RenderTexture EyeCubemap;
    public RenderTexture EquirectTexture;

    void Update ()
    {
        Camera.RenderToCubemap(EyeCubemap, 63, Camera.MonoOrStereoscopicEye.Mono);
        EyeCubemap.ConvertToEquirect(EquirectTexture, Camera.MonoOrStereoscopicEye.Mono);
    }
}

Показанный выше скрипт рендерит каждый кадр в render texture под названием Equirect, которая будет содержать панорамный скриншот, сохранённый в равнопромежуточной проекции.

Значение 63, использованное в методе RenderToCubemap, означает, что мы хотим делать скриншоты со всех шести граней куба.

И EyeCubemap, и EquirectTexture можно создать или в редакторе, или в коде.


Стерео


Код стереоверсии очень похож, но требует дополнительного шага:

    void Start ()
    {
        Camera.stereoSeparation = 0.064f; // 64mm
    }

    void Update ()
    {
        Camera.RenderToCubemap(EyeCubemap, 63, Camera.MonoOrStereoscopicEye.Left);
        EyeCubemap.ConvertToEquirect(EquirectTexture, Camera.MonoOrStereoscopicEye.Left);

        Camera.RenderToCubemap(EyeCubemap, 63, Camera.MonoOrStereoscopicEye.Right);
        EyeCubemap.ConvertToEquirect(EquirectTexture, Camera.MonoOrStereoscopicEye.Right);
    }

Для рендеринга стереоизображения нужно отрендерить две кубические карты. stereoSeparation задаёт расстояние между этими кубическими картами. Стандартное значение — 64 мм, что примерно равно расстоянию между левым и правым глазом.


Создание и сохранение текстур


Два представленных выше фрагмента кода просто выполняют запись в текстуру, но никуда её не сохраняют. Если мы хотим, чтобы кадры сохранялись на диск, то это нужно делать вручную.

К сожалению, экспорт render texture в файл PNG — не такой простой процесс, каким он должен быть. Первая проблема заключается в том, что Unity не позволяет напрямую получать доступ к отдельным пикселям RenderTexture. Сначала render texture нужно скопировать в объект Texture2D.

Фрагмент кода ниже выполняет именно эту задачу, при помощи метода ReadPixels копирует пиксели из текущей активной render texture.

public string FileName;

void Update ()
{
    ...    

    // Creates buffer
    Texture2D tempTexture = new Texture2D(EquirectTexture.width, Equirect.height);

    // Copies EquirectTexture into the tempTexture
    RenderTexture currentActiveRT = RenderTexture.active;
    RenderTexture.active = EquirectTexture;
    TempTexture.ReadPixels(new Rect(0, 0, EquirectTexture.width, EquirectTexture.height), 0, 0);

    // Exports to a PNG
    var bytes = tempTexture.EncodeToPNG();
    System.IO.File.WriteAllBytes(FileName, bytes);

    // Restores the active render texture
    RenderTexture.active = currentActiveRT;
}

При условии, что FileName содержит правильный путь к файлу PNG, представленный выше код выполнит всё необходимое. Нужно будет внести только одно небольшое изменение: сделать так, чтобы скрипт снова и снова не перезаписывал один и тот же файл. Для этого достаточно просто добавить к имени файла счётчик, чтобы многократного переписывания frame.png он выполнял запись в frame_0.png, frame_1.png, и так далее.

Проблемы


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

Производительность


Рендеринг панорамных кадров в Unity — очень затратная задача. В предложенном мной решении сцена рендерится 6 или 12 раз (в зависимости от формата видео — моно или стерео). Постобработка, необходимая для соединения изображений и сохранения каждого кадра на диск, может снизить производительность в 10-15 раз. Если вы рендерите видео в высоком качестве (8192×8192 пикселя), то каждый отдельный кадр может иметь размер более 100 МБ. Очевидно, что если вы не обладаете очень мощной машиной, то не сможете одновременно выполнять игру в реальном времени и экспортировать панорамные кадры.

Постобработка


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


Аналогично этому, эффекты размытия и bloom тоже вызывают ошибки по краям, демонстрируя существование швов. Простых решений этой проблемы нет, потому что ни один из созданных Unity стеков постобработки не предназначен для работы с панорамными изображениями.

Тем не менее, эффекты размытия и bloom всё равно можно применять в умеренной форме. Если вам необходимы эти эффекты, то лучше всего будет применить их в постпродакшене при помощи Premiere Pro.

Line Renderers


Огромная проблем панорамных изображений заключается в том, что могут некорректно отображаться line renderers. Если линия настроена так, что она постоянно должна смотреть на камеру, то при рендеринге её в панорамном изображении Unity просто отбросит её. Это чрезвычайно раздражает, потому что реальных причин для этого нет.

Unity разработала альтернативную версию line renderer под названием XRLineRenderer, которая работает корректно. Хоть она и не поддерживает все функции стандартного компонента Line Renderer, большинство функций вам реализовать удастся

У XRLineRenderer также имеется возможность создания простых эффектов свечения, что может снизить важность описанных в предыдущем разделе проблем.

См. также:

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
+8
Комментарии1

Публикации

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн