Создание кроссплатформенной игры WebGL с помощью Babylon.js
Опубликовано: 2022-03-10Вот вам задание: как насчет создания 3D-игры за выходные? Babylon.js — это JavaScript-фреймворк для создания 3D-игр с использованием HTML5, WebGL и веб-аудио , созданный вашим покорным слугой и командой Babylon.js. Чтобы отпраздновать выпуск новой версии библиотеки 2.3, мы решили создать новую демонстрацию под названием «Sponza», чтобы показать, что можно сделать с помощью движка WebGL и HTML5, когда дело доходит до создания отличных игр в наши дни.
Идея заключалась в том, чтобы создать согласованный, похожий, если не идентичный, опыт на всех платформах, поддерживаемых WebGL, и попытаться использовать возможности нативных приложений. В этой статье я объясню, как все это работает вместе, а также различные проблемы, с которыми мы столкнулись, и уроки, которые мы извлекли при ее создании.
Дальнейшее чтение на SmashingMag:
- Создание шейдеров с помощью Babylon.js
- Использование Gamepad API в веб-играх
- Введение в полигональное моделирование и Three.js
- Как создать отзывчивую 8-битную драм-машину
Для достижения этой цели Sponza использует ряд функций HTML5, таких как WebGL, веб-аудио, а также события указателя (теперь они широко поддерживаются благодаря полифиллу jQuery PEP), Gamepad API, IndexedDB, HTML5 AppCache, переход/анимация CSS3, flexbox и полноэкранный режим. API. Вы можете протестировать демоверсию Sponza на настольном компьютере, мобильном телефоне или Xbox One.
Знакомство с демонстрацией
Во-первых, вы начнете с автоматически анимированной последовательности, отдавая должное тому, кто построил сцену. Большинство членов команды пришли с демо-сцены. Вы обнаружите, что это важная часть культуры 3D-разработчиков. Со своей стороны, я был на Atari, а Дэвид Катухе на Amiga, что до сих пор является постоянным источником конфликтов между нами, хотите верьте, хотите нет. Я немного кодировал, но в основном сочинял музыку для своей демо-группы. Я был большим поклонником Future Crew и особенно Purple Motion, моего любимого композитора демо-сцен всех времен. Но не будем отклоняться от темы.
Вот участники Sponza:
- Мишель Руссо , также известный как «Митч», выполнил замечательную визуальную анимацию и оптимизацию рендеринга, выступая в роли 3D-художника. Он взял модель Sponza, бесплатно предоставленную Crytek на их веб-сайте, и использовал экспортер 3DS Max для создания того, что вы видите.
- Мы с Дэвидом Катухе, также известным как «deltakosh», сделали основную часть движка Babylon.js, а также весь код для демонстрации (пользовательский загрузчик, специальные эффекты для демонстрационного режима с использованием постобработки перехода в черный цвет и т. д.), а также новый тип камеры под названием « Универсальная камера», обрабатывающий все типы входных данных общим способом.
- Я написал музыку, используя Renoise и звуковой банк EastWest Symphonic Orchestra. Если вам интересно, я уже поделился своим рабочим процессом и процессом в статье «Сочинение музыки для игры World Monger для Windows 8 с использованием трекера Renoise и плагинов East West VST».
- Жюльен Моро-Матис помог нам, создав новый инструмент, который поможет 3D-художникам завершить работу между инструментами моделирования (3DS Max, Blender) и конечным результатом. Например, Мишель использовал его для тестирования и настройки различных анимированных камер, а также для добавления частиц в сцену.
Если вы дождетесь окончания автоматической последовательности до «эпического финиша», вы автоматически переключитесь в интерактивный режим. Если вы хотите обойти демонстрационный режим, просто щелкните значок камеры или нажмите A
на геймпаде.
В интерактивном режиме, если вы работаете на Mac или ПК, вы сможете перемещаться внутри сцены с помощью клавиатуры/мыши, как в игре FPS. Если вы используете смартфон, вы сможете перемещаться одним касанием (и 2
, чтобы повернуть камеру). Наконец, на Xbox One вы можете использовать геймпад (или рабочий стол, если вы подключаете к нему геймпад). Забавный факт: на сенсорном ПК с Windows потенциально можно использовать 3 типа ввода одновременно.
Атмосфера отличается в интерактивном режиме. У вас есть три источника звука шторма, случайно расположенные в трехмерной среде, дуновения ветра и трещины от огня в каждом углу. В поддерживаемых браузерах (Chrome, Firefox, Opera и Safari) вы даже можете переключаться между обычным режимом динамика и режимом наушников, щелкнув специальный значок. Затем он будет использовать бинауральный звуковой рендеринг Web Audio для более реалистичного звукового моделирования — если вы слушаете через наушники.
Чтобы получить полный опыт работы с приложением, мы создали значки и плитки для всех платформ. Это означает, например, что в Windows 8 ⁄ 10 вы можете закрепить веб-приложение в меню «Пуск». У нас даже есть несколько размеров:
Сначала офлайн!
После того, как демоверсия будет полностью загружена, вы можете переключить свой телефон в режим полета, чтобы отключить соединение, и щелкнуть значок Sponza. Веб-приложение по-прежнему будет обеспечивать полноценный рендеринг WebGL, трехмерное веб-аудио и поддержку сенсорного ввода. Переключите его в полноэкранный режим, и вы буквально не сможете почувствовать разницу между демоверсией и нативным приложением.
Для этого мы используем слой IndexedDB, изначально доступный внутри Babylon.js. Сцена (формат JSON) и ресурсы (текстуры JPG/PNG, а также MP3 для музыки и звуков) хранятся в IDB. Затем уровень IDB в сочетании с кешем приложений HTML5 обеспечивает работу в автономном режиме. Чтобы узнать больше об этой части и о том, как настроить игру для получения аналогичных результатов, вы можете прочитать статью об использовании IndexedDB для обработки ваших 3D-ресурсов WebGL: обмен отзывами и советами о Babylon.JS и ресурсах кэширования в IndexedDB в Babylon.js.
Xbox One наслаждается шоу
И последнее, но не менее важное: та же демонстрация безупречно работает в MS Edge на Xbox One:
Нажмите A
, чтобы переключиться в интерактивный режим . Xbox One сообщит вам, что теперь вы можете перемещаться с помощью геймпада внутри 3D-сцены:
Итак, коротко подведем итоги.
Одна и та же кодовая база работает на Mac, Linux, Windows в MS Edge, Chrome, Firefox, Opera и Safari, на iPhone/iPad, на устройствах Android с Chrome или Firefox, Firefox OS и на Xbox One! Разве это не круто? Возможность настроить таргетинг на такое количество устройств с полноценным родным интерфейсом прямо с вашего веб-сервера?
Я уже поделился своим волнением по поводу потенциала технологии в предыдущей статье в Интернете: следующий игровой рубеж?
Взломайте сцену с помощью отладочного слоя
Если вы хотите понять, как Мишель овладевает магией 3D-моделирования, вы можете взломать сцену с помощью инструмента Debug Layer в Babylon.js. Чтобы включить его на компьютере с клавиатурой, нажмите CMD/CTRL + SHIFT + D
, а если вы используете геймпад на ПК или Xbox, нажмите Y
. Обратите внимание, что отображение слоя отладки снижает производительность из-за работы по композиции, которую должен выполнять механизм рендеринга. Таким образом, отображаемый FPS немного менее важен, чем реальный FPS, который у вас есть без отображения слоя отладки.
Например, давайте проверим это на ПК.
Подойдите к голове льва и вырежьте канал рельефа из конвейера нашего шейдера:
Вы должны увидеть, что голова теперь менее реалистична. Воспроизведите другой канал, чтобы проверить, что происходит.
Вы также можете отключить динамический движок молнии или отключить движок столкновений, чтобы летать или двигаться сквозь стены. Например, снимите флажок « столкновения » и летите на первый этаж. Поставьте камеру перед красными флажками. Вы можете видеть, как они слегка двигаются. Мишель использовал поддержку костей/скелетов в Babylon.js для их перемещения. Теперь отключите опцию « скелеты », и они должны перестать двигаться:
Наконец, вы можете отобразить дерево мешей в правом верхнем углу. Вы можете включить или отключить их, чтобы полностью сломать работу, проделанную Мишелем:
Удаление геометрии, каналов шейдера или некоторых параметров движка может помочь вам устранить неполадки производительности на конкретном устройстве, чтобы увидеть, что в настоящее время стоит слишком дорого. Вы также можете проверить, ограничены ли вы ЦП или ГП, хотя большую часть времени вы будете ограничены ЦП в WebGL из-за однопоточной природы JavaScript. Наконец, этот инструмент также очень полезен, чтобы помочь вам узнать, как сцена была построена 3D-художником.
Кстати, на Xbox One тоже неплохо работает:
Проблемы
По пути мы столкнулись с рядом проблем и проблем при создании демоверсии. Давайте подробно рассмотрим некоторые из них.
Производительность WebGL и кроссплатформенная совместимость
Со стороны программирования было, вероятно, проще всего справиться, так как она полностью обрабатывается самим движком Babylon.js. Мы используем собственную архитектуру шейдера, которая адаптируется к платформе , пытаясь найти лучший шейдер, доступный для текущего браузера/графического процессора, используя различные резервные варианты. Идея состоит в том, чтобы снизить качество и сложность движка рендеринга до тех пор, пока нам не удастся отобразить что-то осмысленное на экране.
Babylon.js в основном основан на WebGL 1.0, чтобы гарантировать, что 3D-приложения, созданные на его основе, будут работать практически везде. Он был создан с учетом веб-философии, поэтому мы постепенно совершенствуем процесс компиляции шейдеров. Это совершенно прозрачно для 3D-художника, который большую часть времени не хочет иметь дело с этими сложностями.
Тем не менее, 3D-художник играет очень важную роль в оптимизации производительности. Она должна знать платформу, на которую ориентируется, поддерживаемые функции и ограничения. Вы не можете взять активы из игр AAA, созданных для высокопроизводительных графических процессоров и DirectX 12, и просто интегрировать их в игру, работающую на движке WebGL. Я бы сказал, что ориентация на WebGL сегодня очень похожа на работу, которую вам придется проделать для оптимизации работы на мобильных устройствах, с добавлением дополнительного JavaScript, который должен быть многопоточным.
Митч очень хорош в этом: оптимизация текстур, предварительный расчет молнии, чтобы запечь ее в текстуры, максимальное сокращение количества вызовов отрисовки и т. д. У него за плечами многолетний опыт, и он видел различные поколения 3D-оборудование и движки (от PowerVR/3DFX до современных графических процессоров), которые действительно помогли сделать демонстрацию реальностью.
Он уже поделился некоторыми из этих основ в своих статьях о Real Time 3D: создание демо для WebGL Purposes-Basics и уже несколько раз доказал, что вы можете создавать довольно увлекательные визуальные эффекты в Интернете с высокой производительностью на небольших интегрированных графических процессорах, например, в Особняк, Хилл-Вэлли или демо-сцены Espilit. Если вам интересно, найдите время, чтобы посмотреть его выступление на NGF2014 — Создание 3D-ресурсов для мобильного мира и Интернета, точку зрения 3D-дизайнера, где он поделился своим опытом и тем, как ему удалось оптимизировать сцену Hill Valley из менее 1 кадра в секунду до 60 кадров в секунду.
Первоначальной целью Sponza было создание двух сцен. Один для настольных компьютеров и один для мобильных устройств с меньшей сложностью, меньшими текстурами и более простыми сетками и геометрией. Но во время наших тестов мы, наконец, обнаружили, что настольная версия также довольно хорошо работает на мобильных устройствах, поскольку она может работать со скоростью до 60 кадров в секунду на iPhone 6s или Android OnePlus 2. Затем мы решили не продолжать работу над более простой мобильной версией.
Но опять же, вероятно, было бы лучше иметь чистый мобильный подход к Sponza, чтобы достичь 30 кадров в секунду + на многих мобильных устройствах, а затем улучшить сцену для мобильных и настольных компьютеров высокого класса. Тем не менее, большая часть отзывов, которые мы получили на данный момент в Твиттере, указывает на то, что окончательный результат очень хорошо работает на большинстве устройств. По общему признанию, Sponza была оптимизирована для графического процессора HD4000 (интегрированный Intel Core i5), который более или менее эквивалентен графическим процессорам реальных мобильных телефонов высокого класса.
Мы были очень довольны результатами, которых нам удалось достичь. Sponza использует наш шейдер с включенными параметрами Ambient , Diffuse , Bump , Specular и Reflection . У нас есть несколько частиц для имитации небольших пожаров на каждом углу, анимированные кости для красных флажков, звуки 3D-позиционирования и столкновения при движении в интерактивном режиме.
С технической точки зрения, у нас в сцене используется 98 мешей , генерирующих до 377781 вершины, 16 активных костей, более 60 частиц, которые могут генерировать до 36 вызовов отрисовки. Чему мы научились? Одно можно сказать наверняка: меньшее количество вызовов отрисовки является ключом к оптимальной производительности, особенно в Интернете.
Загрузчик
Для Sponza мы хотели создать новый загрузчик, отличный от стандартного, который мы используем на веб-сайте BabylonJS, чтобы иметь чистое и отточенное веб-приложение. Затем я попросил Мишеля предложить что-то новое.
Сначала он прислал мне следующий экран:
Действительно, экран выглядит очень красиво, когда вы впервые смотрите на него. Но затем вы можете начать задаваться вопросом, как заставить его работать на всех устройствах по-настоящему отзывчивым образом? Давайте разберемся.
Давайте сначала поговорим о фоне. Эффект размытия, созданный Мишелем, был хорош, но не работал хорошо во всех размерах и разрешениях окна, создавая некоторый муар. Затем я заменил его «классическим» скриншотом сцены. Однако я хотел, чтобы фон полностью заполнял экран без черных полос и без растягивания изображения, чтобы нарушить соотношение сторон.
Решение в основном исходит из background-size: cover
+ центрирование изображения по осям X и Y. В результате у нас есть опыт, который я искал, независимо от используемого соотношения экрана:
Другие части используют старое доброе процентное позиционирование CSS. Хорошо, разобравшись с этим, как нам обращаться с типографикой — размер шрифта должен основываться на размере области просмотра. Очевидно, для этого мы можем использовать единицы измерения окна просмотра. vw
и vh
(где 1vw — это 1% ширины области просмотра, а 1vh — 1% высоты области просмотра) довольно хорошо поддерживаются во всех браузерах, в частности, во всех браузерах, совместимых с WebGL. (Есть также статья о типографике размера области просмотра в Smashing Magazine, которую я настоятельно рекомендую вам прочитать.)
Наконец, мы играем со свойством opacity
фонового изображения, чтобы изменить его от 0
до 1
в зависимости от текущего процесса загрузки, перемещающегося от 0 до 100%.
Да, кстати, текстовая анимация просто выполняется с использованием CSS-переходов или анимации в сочетании с макетом flexbox, чтобы иметь простой, но эффективный способ отображения в центре или в каждом углу.
Прозрачная обработка всех входных данных
Наш движок WebGL выполняет всю работу на стороне рендеринга, чтобы правильно отображать визуальные эффекты на всех платформах. Но как мы можем гарантировать, что пользователь сможет перемещаться внутри сцены независимо от используемого типа ввода?
В предыдущей версии Babylon.js мы поддерживали все типы ввода и взаимодействия с пользователем: клавиатура/мышь, сенсорный ввод, виртуальные сенсорные джойстики, геймпад, виртуальная ориентация устройства (для Card Board) и WebVR, каждый через специальную камеру. Вы можете прочитать нашу документацию, чтобы узнать о них немного больше.
Touch повсеместно управляется с помощью спецификации Pointer Events, распространяемой на все платформы с помощью полифилла jQuery PEP (при необходимости генерируется Touch Events для приложения). Чтобы узнать больше о событиях указателя, вы можете прочитать об объединении сенсорного управления и мыши: как события указателя упростят поддержку касания в разных браузерах.
Тогда вернемся к демо. Идея Sponza заключалась в том, чтобы иметь уникальную камеру, которая одновременно обрабатывала бы все сценарии пользователей: настольные, мобильные и консольные.
В итоге мы создали UniversalCamera . Если честно, это было настолько очевидно и просто в создании, что я до сих пор не понимаю, почему мы не сделали этого раньше. UniversalCamera — это более или менее камера геймпада, расширяющая TouchCamera , которая расширяет FreeCamera .
FreeCamera обеспечивает логику клавиатуры/мыши; TouchCamera обеспечивает сенсорную логику, а последнее расширение обеспечивает логику геймпада.
UniversalCamera теперь используется в Babylon.js по умолчанию. Если вы просматриваете демоверсии, вы можете перемещаться внутри сцен с помощью мыши, касания и геймпада на всех из них. Опять же, вы можете изучить код, чтобы увидеть, как именно это делается.
Синхронизация переходов с музыкой
В этой части мы задали себе больше всего вопросов. Вы могли заметить, что последовательность вступления синхронизирована с определенными участками музыкальной дорожки . Первые строки отображаются, когда вступают некоторые из барабанов, а финальная последовательность быстро переключается с одной камеры на другую на каждой ноте валторны, которую мы используем.
Синхронизировать звук с циклом рендеринга WebGL непросто. Опять же, это однопоточная природа JavaScript, которая создает эту сложность. В статьях «Введение в веб-воркеры HTML5: многопоточный подход JavaScript» есть некоторые идеи, лежащие в основе этого. Очень важно понять проблему, чтобы понять глобальную проблему, с которой мы сталкиваемся, но подробное рассмотрение здесь выходит за рамки этой статьи.
Обычно в демонстрационных сценах (и видеоиграх), если вы хотите синхронизировать визуальные эффекты со звуками/музыкой, вы будете управляться звуковым стеком. Часто используются два подхода:
- Сгенерируйте метаданные, которые будут вставлены в аудиофайлы, а затем могут «вызывать» некоторые события, когда вы достигаете определенной их части,
- Анализ аудиопотока в реальном времени с помощью БПФ или аналогичных технологий для обнаружения интересных пиков или изменений BPM, которые снова генерируют события для визуального движка.
Эти подходы особенно хорошо работают в многопоточных средах, таких как C++. Но в JavaScript с веб-аудио у нас есть две проблемы:
- JavaScript, который является однопоточным и, к сожалению, большую часть времени веб-воркеры нам особо не помогут,
- Веб-аудио не имеет событий , которые можно было бы отправить обратно в поток пользовательского интерфейса, даже если веб-аудио обрабатывается браузером в отдельном потоке.
Веб-аудио имеет гораздо более точный таймер, чем JavaScript. Было бы здорово иметь возможность использовать этот отдельный таймер в отдельном потоке для передачи событий обратно в поток пользовательского интерфейса. Но сегодня вы не можете этого сделать (пока?).
С другой стороны, мы рендерим сцену, используя WebGL и метод requestAnimationFrame
. Это означает, что в «лучших случаях» у нас есть таймфрейм окна 16 мс. Если вы пропустили один из них, вам придется подождать до 16 мс, чтобы иметь возможность воздействовать на следующий кадр, чтобы отразить синхронизацию звука (например, запустить эффект «затухание до черного»).
Затем я подумал о внедрении логики синхронизации в цикл requestAnimationFrame
. Я изучил время, прошедшее с начала последовательности, и изучил возможность настройки визуальной реакции на звуковое событие. Хорошей новостью является то, что веб-аудио воспроизводит звук независимо от того, что происходит в основном потоке пользовательского интерфейса. Например, вы можете быть уверены, что 12-секундная временная метка музыки будет получена ровно через 12 секунд после начала воспроизведения музыки, даже если GPU испытывает трудности с рендерингом сцены.
В конце концов, мы, наконец, выбрали самое простое решение: использование вызовов setTimeout()
! Да, я знаю. Если вы посмотрите на большинство статей, включая ту, на которую я ссылался выше, вы обнаружите, что это довольно ненадежно. Но в нашем случае, когда сцена готова к рендерингу, мы знаем, что загрузили все наши ресурсы (текстуры и звуки) и скомпилировали наши шейдеры. Нас не должны слишком раздражать неожиданные события, переполняющие поток пользовательского интерфейса. GC может быть проблемой, но мы также потратили много времени на борьбу с ним в движке: снижение нагрузки на сборщик мусора с помощью панели разработчика F12 в Internet Explorer 11.
Тем не менее, мы знаем, что это решение далеко от идеального. Переключение на другую вкладку или блокировка телефона и разблокировка его через несколько секунд могут вызвать некоторые проблемы в части синхронизации демонстрации. Мы могли бы исправить эти проблемы, используя API видимости страницы, например, приостановив цикл рендеринга, различные звуки и повторно вычислив следующие таймфреймы для вызовов setTimeout()
.
Но, возможно, мы что-то упустили; возможно, и даже вероятно, существовал лучший подход к решению этой проблемы. Мы будем рады услышать ваши мысли и предложения в разделе комментариев, если вы считаете, что есть лучший способ решить ту же проблему.
Обработка веб-аудио на iOS
Последняя проблема, которой я хотел бы поделиться с вами, — это то, как веб-аудио обрабатывается iOS на iPhone и iPad. Если вы ищете статьи о «веб-аудио + iOS», вы обнаружите, что многим людям трудно воспроизводить звуки на iOS. Что там происходит?
iOS имеет замечательную поддержку веб-аудио — даже режим бинаурального звука. Но Apple решила, что веб-страница не может воспроизводить звук по умолчанию без определенного взаимодействия с пользователем. Это решение, вероятно, было принято для того, чтобы реклама или что-то еще не мешало пользователю воспроизводить нежелательные звуки.
Что это значит для веб-разработчиков? Что ж, сначала вам нужно разблокировать контекст веб-аудио iOS после прикосновения пользователя — прежде чем пытаться воспроизвести какой-либо звук. В противном случае ваше веб-приложение останется отчаянно немым.
К сожалению, единственный способ, который я нашел, чтобы сделать эту проверку, - это использовать подход обнюхивания пользовательской платформы, поскольку я не нашел способ обнаружения функций для этого. Это не что иное, как ужасные, а не пуленепробиваемые методы, но я не мог найти другого решения, которое решило бы проблему. Код? Ну вот!
Если вы не используете iPad/iPhone/iPod, аудиоконтекст сразу же доступен для использования. В противном случае мы разблокируем аудиоконтекст iOS, проигрывая сгенерированный кодом пустой звук в событии touchend . Вы можете зарегистрироваться на событие onAudioUnlocked , если хотите дождаться его перед запуском игры. Итак, если вы запускаете Sponza на iPhone/iPad, у вас будет этот последний экран в конце последовательности загрузки:
Прикосновение к любому месту на экране разблокирует звуковой стек iOS и запустит «шоу».
Итак, поехали! Я надеюсь, что вам понравились некоторые идеи о разработке демоверсии. Чтобы узнать больше, прочитайте полный исходный код этой демонстрации на нашем GitHub. Очевидно, что все с открытым исходным кодом, и вы можете найти основные файлы на GitHub: index.js и babylon.demo.ts.
Наконец, я очень надеюсь, что теперь вы еще больше убедитесь в том, что Интернет, безусловно, является отличной платформой для игр! Оставайтесь с нами, так как в данный момент мы работаем над новыми демонстрациями, и, надеюсь, они тоже будут весьма впечатляющими.
Эта статья является частью серии веб-разработок от технических евангелистов и инженеров Microsoft, посвященных практическому изучению JavaScript, проектам с открытым исходным кодом и передовым методам взаимодействия, включая браузер Microsoft Edge.Мы рекомендуем вам проводить тестирование в разных браузерах и на разных устройствах, включая Microsoft Edge — браузер по умолчанию для Windows 10 — с бесплатными инструментами на сайте dev.microsoftedge.com, включая инструменты разработчика F12 — семь отдельных, полностью документированных инструментов, которые помогут вам отлаживать, тестировать и ускорить ваши веб-страницы. Кроме того, посетите блог Edge, чтобы быть в курсе событий и получать информацию от разработчиков и экспертов Microsoft.