
A-Frame — это фреймворк для создания виртуальной реальности в вебе. Используя лишь ссылку, любой человек с VR-шлемом или поддерживающим VR смартфоном может погрузиться в 3D пространство. Tone.js — это JavaScript библиотека для создания звуков. Давайте взглянем, что будет, если их совместить.
Для начала, мы создадим окружение, с A-frame это очень просто. Используя лишь базовый HTML, мы можем создать целое 3D пространство, для этого нам нужен aframe-environment-component. Ниже приведена базовая разметка для наших целей.
<!DOCTYPE html> <html> <head> <title>Basic Scene with Environment - A-Frame</title> <meta name="description" content="Basic Scene with Environment - A-Frame"> <script src="https://aframe.io/releases/1.0.4/aframe.min.js"> </script> <script src="https://unpkg.com/aframe-environment-component@1.1.0/dist/aframe-environment-component.min.js"></script> </head> <body> <a-scene environment="preset: starry"> <a-camera> <a-entity cursor="fuse: true; fuseTimeout: 500" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03" material="color: black; shader: flat"> </a-entity> </a-camera> </a-scene> </body> </html>
Обратите внимание на элемент:
<a-entity cursor>
Он находится внутри нашей камеры. Чуть позже он позволит общаться с нашим синтезатором. Но перед тем, как приступить, стоит убедиться в корректной загрузке проекта.
Открывая страницу, вы должны увидеть трехмерное небо, звезды и сетку на земле. Все это было создано aframe-environment-component, когда мы задали окружение:
<a-scene environment=”preset: starry”>
При желании окружение можно поменять, достаточно добавить другой шаблон. На момент написания этой статьи существуют 16 разных шаблонов окружения на ваш выбор.

Мне нравится, что наш синтезатор находится в космосе, космос — это круто. Давайте сделаем так, чтобы наше окружение больше напоминало поверхность планеты.
Для начала мы удалим сетку и добавим текстуру земли, изменив:
<a-scene environment="preset: starry">
на
<a-scene environment="preset: starry; grid: none; groundTexture: walkernoise">
Запустив страницу сейчас, мы увидим, что наша планета все еще слишком темна, чтобы разглядеть что-то на земле. Исправим это, добавив источник света в нашу сцену.
<a-entity light="type: ambient; color: #CCC"></a-entity>
С ним сцена должна выглядеть примерно так:

Теперь, когда мы разобрались с окружением, давайте начнем разрабатывать синтезатор.
Создание компонента
A-Frame построен на entity-component-system. Она позволяет создавать компоненты и добавлять их к сущностям в нашей сцене.
Давайте создадим файл synth.js для нашего компонента.
AFRAME.registerComponent('synth', { schema: { // Описание свойств компонента. }, init: function () { // Действия при первом присоединении компонента. }, update: function () { // Действия при обновлении данных компонента. }, remove: function () { // Действия при отсоединении компонента или его сущности. }, tick: function (time, timeDelta) { // Действия при каждой итерации (тике) или кадре. } });
Как вы можете видеть, в A-Frame встроены методы жизненного цикла, это облегчает добавление интерактивности в наши WebVR проекты. База компонента готова, давайте взглянем на процесс создания синтезатора с Tone.js.
Tone.js
Tone.js — фреймворк, предназначенный для создания интерактивной музыки в браузере, является оболочкой для Web Audio API. Создание синтезатора с tone.js просто — достаточно лишь написать строку:
var synth = new Tone.Synth().toMaster()
Но мы создадим осциллятор и добавим несколько параметров для упрощения дальнейшей кастомизации:
const synth = new Tone.Synth({ volume: -15, // -15dB oscillator: { type: 'triangle' // тип осциллятора - волна "треугольник" }, envelope: { attack: 0.05, // атака - начало звука release: 2 // релиз - затухание } }).toMaster()
Добавим этот код прямо поверх нашего компонента в файле synth.js. Теперь синтезатор у нас есть, но нам нужно предоставить нашему компоненту способ к нему обратиться. Помните <a-entity cursor>, который мы добавили к камере? У это курсора есть параметр fuse=«true». Это позволит нам следить за тем, как курсор взаимодействует с сущностями. Добавим EventListener к компоненту для fuse.
Мы создадим EventListener в методе init жизненного цикла и создадим новый метод с названием trigger, запускающий Tone.js.
... init: function () { // добавляем EventListener к нашему элементу для fuse this.el.addEventListener('fusing', this.trigger.bind(this)) }, // создаем метод, запускающий tone.js trigger: function () { //tone.js функция, запускающая синтезатор с нашими параметрами synth.triggerAttackRelease(this.data.note, this.data.duration) }, ...
Добавляем компонент синтезатора в сцену
Мы создали компонент, самое время добавить его в сцену A-Frame.
Для начала добавил Tone.js и компонент синтезатора в нашу разметку. Обратите внимание на порядок подключения файлов — synth.js загружается после Tone.js.
... <script src="https://unpkg.com/tone@13.8.25/build/Tone.js"></script> <script src="synth.js"></script> </head> ...
Нам так же нужны несколько сущностей, к которым мы присоединим компонент. Добавим несколько стандартных фигур A-Frame для использования в нашей сцене.
<a-scene> ... <a-box synth="note: E4" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box> <a-sphere synth="note: C4" position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere> <a-cylinder synth="note: G4" position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder> ...
Обратите внимание на атрибут synth. Это созданный нами компонент. ‘Synth’ — это имя, зарегистрированное нами с
AFRAME.registerComponent(‘synth’, {})
а “note” мы объявили в схеме компонента. Так же есть свойство “duration” — мы можем использовать его для изменения длины ноты. Например:
synth=«note: E4; duration: 8n»
сыграет 1/8 от целой ноты, а не стандартную 1/4.
Теперь открыв сцену в браузере мы увидим наши фигуры, а при наведении на них курсора должна проиграться нота с нашего компонента синтезатора.

Используем контроллер Oculus Go
Сейчас наша сцена работает так — курсор фиксирован в центре экрана. На VR шлемах это называется “зрительное” управление. Поворачивая голову, курсор будет перемещаться в направлении движения пользователя. Это абсолютно нормальный опыт и хорошо работает для многих проектов. Но что если мы хотим управлять синтезатором с помощью VR контроллера? Двигать руками вокруг и создавать музыку — звучит весело, поэтому давайте изменим нашу сцену, чтобы она использовала контроллер Oculus Go.
Для начала стоит добавить несколько сущностей в нашу сцену — контроллер и raycaster.
... <a-entity oculus-go-controls> <a-entity laser-controls raycaster="far: 200; interval: 100"></a-entity> ...
Тут мы имеем собственную сущность для управления Oculus Go, а также одну для raycaster, который будет запускаться каждые 100 миллисекунд.
Теперь давайте модифицируем компонент синтезатора для управления Oculus. Сделаем это, добавив raycaster в зависимости нашего компонента.
AFRAME.registerComponent('synth', { dependencies: ['raycaster'], ...
Затем, в методе init поменяем EventListener — он должен отслеживать событие:
raycaster-intersection
init: function () { this.el.addEventListener('raycaster-intersection', this.trigger.bind(this)) }, ...
Запуск сцены в Oculus Go теперь должен показывать ваш контроллер — а лазерное управление должно запускать синтезатор, играющий ноты при наведении на фигуры.

Если вы хотите поближе ознакомиться с проектом, вы можете запустить его и посмотреть исходный код здесь — glitch.com/~space-synth-vr
В заключении
Теперь мы имеем простую сцену с VR синтезатором и есть огромное количество возможностей ее улучшить. Мы можем добавлять больше объектов для взаимодействия, больше синтезаторов и эффектов для компонента. Мы можем анимировать объекты, основываясь на каких-то событиях. По мере увеличения сцены, стоит думать о производительности. К счастью, в A-Frame много встроенных функций, способных помочь с этой проблемой.
Вот несколько полезных ссылок
Компоненты
Raycaster
Взаимодействие и контроль
Tone.js
Исходный код проекта
Спасибо за прочтение.
ссылка на оригинал статьи https://habr.com/ru/post/500188/
Добавить комментарий