Введение
В феврале 2020 года началась пандемия, мы перешли на удалённый формат работы и очень быстро освоили новый поведенческий паттерн взаимодействия друг с другом в формате онлайн с помощью сервисов ВКС. Однако со временем недостаток живого общения и ощущения физического присутствия начали приводить к эмоциональному выгоранию, снижению мотивации и общей продуктивности.
Мы с коллегами из команды RnD XR (extended reality) департамента SberDevices начали думать, как можно использовать технологии 3D и XR для повышения качества взаимодействия команд на ежедневных видеовстречах в SberJazz. Так родилась идея решения SberJazz XR.
О продукте
SberJazz XR — разработан на базе платформы видеовстреч SberJazz (подробнее про сервис можно почитать тут). Решение позволяет пользователям создавать виртуальные 3D-встречи, в которых можно коммуницировать, работать или просто отдыхать и развлекаться вместе, взаимодействуя друг с другом посредством своих цифровых двойников — 3D-персонажей.
Виртуальные встречи в SberJazz XR — это история про новый иммерсивный формат видеовстреч, про ощущение присутствия и вовлечённости в процесс.
Наша основная цель — объединять людей из разных точек планеты, предоставляя им новый опыт взаимодействия в виртуальных 3D-пространствах, а также комфортный доступ к тем инструментам, которыми они привыкли пользоваться.
Важной задачей было сделать сервис максимально простым и доступным каждому. Подключиться к виртуальной встрече в 3D так же просто, как и к классической встрече в аудио- и видеоформате. Сейчас SberJazz XR доступен пользователям в браузере на ПК WIndows и Mac без необходимости скачивания дополнительного программного обеспечения. В ближайшей перспективе рассматриваем возможность дать пользователям доступ к решению на мобильных платформах и VR, который позволяет достичь максимального эффекта присутствия.
Ключевые возможности
Мы постарались сделать опыт погружения в виртуальные пространства максимально комфортным и удобным. Ниже можно ознакомиться с ключевыми возможностями решения SberJazz XR.
Создание встречи в 3D
Создать 3D-комнату в SberJazz XR могут пользователи с бизнес-лицензией. На этапе создания встречи можно выбрать формат: будет ли это классическая видеовстреча в 2D или встреча в виртуальном 3D-пространстве. Для этого необходимо в браузере нажать «Создать встречу» и включить опцию «Встреча c 3D», после чего отправить ссылку-приглашение на созданную встречу участникам.
Участники переходят по ссылке-приглашению, открывают вкладку «Вид» и нажимают на кнопку «3D». При этом пользователь всегда может переключиться в более комфортный для себя режим: 3D или привычный аудио- и видеоформат в рамках той же самой встречи.
Виртуальные встречи в 3D могут поддерживать до 50 активных участников, представленных собственными 3D-персонажами в виртуальном пространстве.
3D-персонажи
Перед тем как войти в 3D-режим пользователь выбирает своего персонажа. Пока можно выбрать только его гендер — мужской или женский, но в самое ближайшие время мы планируем добавить возможность кастомизации — выбора одежды персонажа, причёски, цвета волос и т.д.
Локации
На текущий момент пользователям при создании 3D-встречи доступна одна локация для проведения конференций до 50 человек (с зоной ожидания начала конференции, сценой и зрительными местами). В перспективе появится возможность выбора локации на этапе создания встречи и под другие пользовательские сценарии.
Управление
Управление привычное для игровых продуктов: перемещаться персонажем по 3D- пространству можно с помощью клавиш WASD или с помощью стрелок. Удерживая левую кнопку или тачпад, можно менять угол обзора. Также с помощью скролла можно изменять режим — переключаться между видом от третьего и от первого лица. Можно прыгать/ бегать и телепортироваться в любую точку пространства по двойному нажатию левой кнопки мыши.
Режим докладчика
Кроме ежедневных рабочих встреч в онлайн-формате, в сервисах ВКС также проводятся конференции, вебинары, презентации продуктов и идей. Основная боль докладчика для такого формата встреч — отсутствие обратной связи от аудитории в реальном времени. Непонятно как реагирует аудитория, интересен ли ей материал, находят ли отклик шутки, какое отношение у слушателей к тем или иным фактам. В виртуальных встречах SberJazz XR такой проблемы больше нет — докладчик всегда находится в зрительном контакте с аудиторией, может наблюдать реакции участников встречи и просто ощущать их вовлечённость в общий процесс.
Участники могут подключаться в виртуальное 3D-пространство по ссылке приглашению до запланированного начала мероприятия и свободно перемещаться, исследовать пространство и взаимодействовать с окружением или друг с другом.
В качестве обратной связи участники встречи могут отправлять реакции — в ответ на какое-либо высказывание спикера. Реакции от участников будут видны как в 2D, так и в 3D режиме. При этом докладчик в режиме реального времени будет видеть счётчик таких реакций и понимать общее настроение аудитории. Такой инструмент полезен, когда нужно провести быстрый опрос или даже голосование.
Живые реакции
Одной из важных фичей SberJazz XR, с точки зрения взаимодействия между пользователями в виртуальном пространстве, являются живые реакции — анимированные реакции 3D-персонажа, дополненные визуальным и аудиальными эффектами. Можно поднять руку, чтобы задать вопрос, поставить лайк, похлопать в ладоши, посмеяться. Кроме этого, можно включить фронтальную камеру — над персонажем появится кружок с видео и в виртуальном пространстве будет понятно кто есть кто. Реакции участников отображаются как в 2D, так и в 3D режиме.
В дальнейшем мы планируем расширять возможности взаимодействия между персонажами — добавить в виртуальный мир больше физики реального мира. Например, возможность пожать другому персонажу руку, похлопать его по плечу или дать пять.
Встраиваем 3D в React приложение
SberJazz XR — кроссплатформенное решение, поэтому отдельно стояла задача имплементации в вебе. Об этом процессе расскажем чуть подробнее.
Разработку мы ведем с использованием движка Unity. Сам по себе процесс разработки приложений в среде Unity с дальнейшим экспортом отдельной WebGL сборки не представляет особых проблем: сборка включает index.html файл, который запускается в браузере.
В нашем случае Unity Instance должен быть реализован не как отдельное приложение, а в качестве артефакта в составе сервиса видеовстреч SberJazz, реализованного с использованием фреймворка React. С самим React также не возникает проблем: если в React приложение вставить: <iframe src={‘../path/to/unity/index.html’}/> с указанием пути до сборки — приложение запускается и корректно функционирует.
В процессе разработки нам также было необходимо решить вопросы:
интеграции Unity приложения в сервис SberJazz и работы с legacy-кодом приложения;
реализации двустороннего протокола общения web и Unity;
передачи видео из web в Unity приложение.
Для удобства мы пользуемся библиотекой react-unity-webgl. В ней доступны все необходимые нам методы для работы с Unity (ну или почти все). Для инициализации Unity Instance используется hook useUnityContext. Полученный unityContext даёт возможность взаимодействовать с Unity Instance, обмениваться сообщениями, отслеживать загрузку и тд.
import { Unity, useUnityContext } from 'react-unity-webgl';
const UnityContent: FC = () => {
const unityContext = useUnityContext({
loaderUrl: `./Build/build_unity.loader.js`,
dataUrl: `./Build/build_unity.data`,
frameworkUrl: `./Build/build_unity.framework.js`,
codeUrl: `./Build/build_unity.wasm`,
streamingAssetsUrl: `./StreamingAssets/`,
companyName: 'SberDevices',
productName: `Jazz XR`,
productVersion: `v.0.0.1`,
});
return <Unity unityProvider={unityContext.unityProvider} />
Для очистки Unity Instance перед размонтированием компонента, в котором он находится, должен был быть использован метод:
unityContext.unload();
Однако данный метод не работает для версий Unity 2021.2 и старше, в связи с известным багом Unity.
Чтобы обойти данное ограничение и иметь возможность выгружать Unity Instance из памяти без ошибок, мы использовали iframe.
const App:FC = () => {
return <iframe>
<UnityConten/>
</iframe>
}
Протокол общения React-Unity
На скриншотах выше можно заметить, что весь UI реализован поверх Unity сцены. Так сделано, в первую очередь потому, что мы встраиваем 3D в уже готовое приложение, а значит, будем транслировать ивенты от имеющегося UI в 3D сцену. Логику делить не стали, продолжили делать UI на React’e. А для отправки сообщений в Unity используем уже созданный контекст
Отправляем сообщения из React в Unity:
function ToggleSounds(isActive: boolean) {
unityContext.sendMessage("SoundController", "ToggleSounds", isActive);
}
// SoundController - это имя объекта внутри сцены
// ToggleSounds - метод написаный на C#, который мы вызываем
// isActive - параметры передаваемые в этот метод (могут быть лишь boolen, string, int)
Принимаем сообщение в Unity:
using UnityEngine;
public class SoundController : MonoBehaviour {
public void ToggleSounds (bool isActive) {
Debug.Log ($"Environment sounds now is {isAcive}");
}
}
Передаем видео внутрь 3D-сцены
Каждый пользователь при входе в 3D-сцену отправляет свои данные по аналогии с переключением звука, среди этих данных есть следующее:
type User =
{
uid: string;
name: string;
cameraMuted: boolean;
screenMuted: boolean;
...
}
Со стороны React в момент включения камеры/выбора повтора экрана создаём Canvas, в который записываем видеопоток и присваиваем ему uid пользователя. Со стороны Unity получаем патч с новыми данными, и, если видим значение cameraMuted: false или screenMuted: false, понимаем, что клиент включил камеру/запустил повтор экрана.
С помощью плагина JSLib мы можем получить доступ к элементам HTML документа, в котором запущен наш Unity Instance. Там мы ищем canvas по uid и копируем текстуру из canvas в заранее выделенную текстуру внутри Unity сцены. Пример реализации можно посмотреть тут.
Синхронизируем информацию между пользователями 3D-встречи
Для синхронизации информации о внешнем виде персонажей между участниками 3D-встречи мы используем риалтайм-сервер: после того как пользователь выберет 3D-персонажа, приложение формирует пакет начальных данных и в момент подключения к риалтайм-серверу отправляет эти данные вместе с запросом.
Цвет одежды персонажа и его скин задаются числами, поскольку выбор цвета и скина персонажа происходит из заранее известного всем клиентам списка. После получения этих данных любой клиент без труда сможет сопоставить конкретного персонажа, его цвет с пользователем. Вот так выглядит начальный пакет данных, отправляемый в момент подключения:
{
roomId: string,
userId: string,
colorId: number,
skinId: number
}
Кроме этого, синхронизируются данные о положении, направлении взгляда и скорости движения персонажей внутри 3D-сцены. Сообщения отправляются клиентами с высокой частотой.
При выборе сетевого фреймворка мы, в первую очередь, обращали внимание на быстродействие протокола обмена данными. При определении структур данных на сервере разработчик задаёт её через, так называемые, схемы данных. Каждый элемент такой схемы — поле класса, отмеченное атрибутом. Такого рода структуры позволяют использовать описанные в схеме данные не только на сервере, но и на клиенте через механизм генерации кода.
Приняв сообщение от клиента, сервер обновляет свою модель данных новыми данными. С определённой периодичностью сервер отправляет всем клиентам обновление с новым состоянием модели комнаты. Вот структура данных, которые пользователи передают на сервер:
{
userId: string,
x: number,
y: number,
z: number
}
А вот структура данных, которую сервер присылает всем клиентам с определенным периодом:
Player:
{
userId: string,
position: Vector3,
direction: Vector3
}
State:
{
players: [Player]
}
Реакции синхронизируются как события от сервера конференции, а не от риалтайм сервера. Это как раз связано с тем, что посылать и принимать реакции можно не только в 3D, но и в обычных конференциях. Примерный формат передачи данных для эмоции выглядит вот так:
{
userId: string,
emotionId: string
}
Собственная zero-code система имплементации логики
Для удобства работы геймдизайнеров мы разработали собственную zero-code систему построения блоков логики. Она позволяет связывать события и их обработчики прямо в визуальном редакторе. Подобные системы сильно развязывают руки программистами и дают возможность другим участниками проекта описывать поведение и настраивать фичи. Вот пример того, как задаются подобные связи:
Технически система построена на трех главных компонентах: событие, реакция и действие.
Событие представляет собой источник информации об изменении состояния системы: клик на кнопку, активация коллайдера, глобальное событие.
Действие задаёт операцию, которую можно выполнить, чтобы изменить состояние системы: создать объект на сцене, активировать систему частиц.
Реакция — это контейнер, главная задача которого связать источники информации и нужные действия.
Со временем мы добавили варианты более сложных конструкций:
стейт-машины — у каждого состояния стейт-машины можно задать условия перехода в другой стейт и действия, выполняемые на входе и выходе из стейта.
условные действия — даже при наступлении определенного события действие может не запуститься, если его условия не выполнены.
контейнеры данных — для реализации сложной логики необходимо хранить промежуточные значения и состояния.
Все обладатели бизнес-лицензий SberJazz уже сейчас могут протестировать новый формат встреч, чтобы удивлять и удивляться.
MAXH0
А еще можно ввести цветовую дифференциацию штанов. "Когда у общества нет цветовой дифференциации штанов, то нет цели! А когда нет цели — нет будущего!" А на штаны можно еще и NFT метки ставить, чтобы подчеркнуть уникальность.
Так что есть куда копать!