Создание пользовательского интерфейса для Blend4Web (ч.1)

Иногда я считаю себя первопроходцем, открывающим новые страницы использования Blend4Web. Это молодой движок, с энергичной командой разработчиков, богатыми возможностями и множеством не очень хорошо документированных функций. Что-то я черпаю из исходников большого количества демо, дергаю разработчиков по всяким вопросам, а чаще всего действую методом «научного тыка». В этой статье я хочу поделиться своими наработками по созданию пользовательского интерфейса для приложения. И что важно, с помощью Blend4Web и HTML5 можно сделать вполне приличный игровой GUI.

1bc646493f2943348c4a72f8812c50fe.jpg
В игре, когда кораблики летают, успешно расстреливая полчища метеоритов и себе подобных, хочется видеть на экране несколько больше, то есть получать какую-либо информацию об игровом процессе. Это всевозможные текстовые сообщения о миссиях или заработанных очках, «полоски жизни» и т.п. Все эти элементы можно создавать двумя способами: с помощью функций HTML/CSS и через Blender/JavaScript.

В декабре 2015 года вышел очередной релиз Blend4Web с любопытной фичей. Разговор идет об инструменте Viewport Alignment — это ничто иное, как инструмент автоматического выравнивания элементов пользовательского интерфейса по отношению к камере. Вроде ничего удивительного, но нужно знать, что традиционно верстка GUI для приложения Blend4Web выполняется с помощью HTML/CSS. Лично мне этот подход кажется неудобным и я предпочитаю делать всё в самом Blender. Раньше это было сложно, так как интерфейс «расползался» при изменении разрешения или пропорций экрана. Теперь есть возможность отказаться от заморочек с HTML и создавать GUI непосредственно в сцене Blender.

Статичные элементы


С точки зрения Blend4Web элемент GUI ничем не отличается от любого объекта в сцене, разве что он привязан к активной камере. Все волшебство выполняется в самом Blender.

Элементы GUI традиционно считают двухмерными, но в случае с Blend4Web они являются всегда трехмерными объектами. Правда выглядеть они могут по разному. Самый простой вариант — создать плоскость (Plane) с натянутой текстурой.

Есть удобный плагин с названием «Import Images as Planes», который входит в базовую комплектацию Blender. Его назначение в создании плоскости с уже готовой текстурой. Он реально убыстряет процесс, ведь достаточно выбрать нужную картинку и она появляется на сцене. Вот только я не советую использовать этот плагин для GUI по одной простой причине — неоптимально. Желательно все нарисованные элементы интерфейса хранить на одной текстуре, т.е. создавать, так называемый, атлас.

Рисовать интерфейс можно в чем угодно, но важно уместить всё на текстуре с одинаковыми пропорциями сторон кратным 4, например 512×512, 1024×1024. Причем не стоит увлекаться размерами. Слишком маленькая текстура — плохо, слишком большая тоже не очень. Так, максимальный размер стоит ограничить разрешением 2048×2048, хотя по мне и этого много. Вообще, хорошим тоном считается выводить элементы интерфейса пиксель в пиксель, безо всякого масштабирования. Но в нашем случае это нереально, ведь каждый элемент является обычным трехмерным объектом.

Так и получается, что создание интерфейса выполняется стандартными средствами Blender. Рассмотрим базовые шаги:

  • Создать примитив Plane (меню ADD | Mesh). Сначала следует переключиться в режим просмотра Camera. Когда вы добавите в сцену Plane, обратите внимание на вспомогательную панель слева с параметрами созданного примитива. Там есть опция Align To View. Если вы активируете ее, то Plane развернется «лицом» к камере.
  • Настроить UV-координаты. Это удобнее выполнять при включенной раскладке окон UV Editing. Выделите свою плоскостью, нажмите клавишу Tab для перехода в режим редактирования и U → Unwrap для установки координат. Только предварительно откройте в соседнем окне нужную текстуру. Теперь, используя стандартные способы перемещения и масштабирования Blender (горячие клавиши G и S), разместите вершины UV вокруг нужного рисунка.

549cddbfda314021bf937c87c5e60bb7.jpg

  • Создать материал и настроить текстуру. В принципе и это действие ничем не отличается от обычной работы с материалами в Blender. Посмотрите на рисунок ниже. Я выделил ключевые опции для настройки текстуры и материала с прозрачностью. Здесь также включена опция Shadeless. Это полезно, если вы хотите, чтобы ваш материал не реагировал на источники света.

2ca9ff4a704946a3a514f9bc5c03e23d.jpg

Итак, в сцене имеется плоскость с текстурой, повернутой в сторону камеры. Настало время рассмотреть инструмент Viewport Alignment (не забудьте, что опции движка Blend4Web станут видны только после выбора рендера с одноименным названием).

Viewport Alignment позволяет «прикрепить» выбранный объект к границам или углам активной камеры. Сделав это действие в Blender, вы будете уверены в том, что элементы интерфейса останутся на своих местах вне зависимости от разрешения экрана.

Сначала нужно создать связь «родитель-ребенок» между вашей плоскостью и самой камерой. Выделите Plane, а затем Camera с нажатой клавишей Shift. В меню Object → Parent выберите пункт Object. Если все сделано правильно, то при перемещении камеры плоскость будет послушно скользить вслед за ней.

И только теперь станут доступными опции Viewport Alignment в панели Object.

197aea590e2a470b85e3b76439108542.jpg

Включите Viewport Alignment и выберите из меню нужную сторону для привязки. Если теперь попробовать экспортировать сцену и просмотреть результат в браузере, то, скорее всего вы получите удивительный результат. Объект «приклеится» к выбранному месту, но, выглядеть это будет совсем не так, как ожидалось.

В панели есть кнопка Fit to Camera. С ее помощью можно разместить объект в соответствии с выбранными параметрами привязки и расстояния (опция Distance). Поэтому, нажав на нее, вы окончательно переместите элемент в нужное место. Есть еще один нюанс, который почему-то не объясняется в официальной документации.

Дело в том, что привязка выполняется в зависимости от центра объекта. И для правильной установки его необходимо сместить в нужную сторону. На рисунке ниже выделен центр элемента, который прижат к верхнему правому углу.

Для смещения центра перейдите в режим редактирования (клавиша Tab) Установите 3D курсор в нужном месте (щелчком левой кнопки мыши) и выберите пункт меню Object → Transform → Origin to 3D Cursor.

4f3e4ee23a64473c8d21ae75e33e0d74.jpg

Таким нехитрым способом вы можете создать любые интерфейсные элементы, привязанные к камере и автоматически меняющие местоположение при смене разрешения экрана

Кстати, хоть я и назвал эту часть урока «Статичные элементы», но ничто вам не мешает создавать любые анимации для элементов GUI. Все это делается стандартными для Blender способами.

Динамичные элементы


Вы думаете, я сейчас начну рассказывать о крутых анимационных эффектах? Нет, оставлю эту благодатную почву другим авторам, а перейду вот к какой теме…

В игре очень часто нужны всякого рода индикаторы: жизни, защиты, нагрева оружия и т.д. Их визуальный вид зависит от текущего действия. Герой богат «жизнью» — длинная полоска, теряет «жизнь» и полоска уменьшается.

Самое простое, что приходит в голову — это создать объектную анимацию, допустим, с изменением масштаба. Но нужно учитывать еще и удобство работы с такой анимацией, ведь размер индикатора должно соответствовать некоторому цифровому значению. Поэтому наиболее выигрышной выглядит изменение геометрии, так называемая вершинная анимация. Причем достаточно создать две формы: начальную и конечную. А переходы между ними выполнять из кода.

Алгоритм создания шейповой анимации (см. рис. ниже):

  • Придать объекту начальную форму.
  • Перейти в панель Object Data и установить базовый ключ (на скриншоте он называется Basis).
  • Добавить новый ключ (key 1) и установить значение Value в единицу.
  • Перейти в режим редактирования и придать объекту конечную форму.
  • Открыть панель Object и включить опцию Export Shape Keys.

11c2619ff8e545809f5f29e99e01bfec.jpg

Если всё сделано правильно, то при изменении значения Value, будет изменяться геометрия объекта.

Здесь-то и заключается магия. API Blend4Web позволяет контролировать параметр Value из кода. Значения его меняются от 0 до 1, поэтому несложно написать функцию адаптации каких-либо цифровых данных применительно к анимации статус-бара.

Небольшой пример:

...
var m_scene = b4w.require("scenes");
var m_geom = b4w.require("geometry");
…
//ищем в сцене объект с именем "Object Name"
var obj = m_scene.get_object_by_name("Object Name");

//устанавливаем значение Value ключа Key 1, как 0.5 (50%)
m_geom.set_shape_key_value(obj , "Key 1", 0.5);
...

Вывод текста


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

На первый взгляд Blend4Web не имеет ничего для вывода текстовой информации на экран, не в виде картинок или 3D, а самого обычного текста. Если честно, то я вначале был поставлен в тупик, когда пытался реализовать простую печать Score. Каких-либо нативных функций в API не нашлось. Зато есть отличный механизм работы с HTML5 Canvas. А уже с его помощью с текстом можно творить чудеса.

Работа с канвой HTML5 в официальной документации движка рассматривается крайне скупо. Некоторые важные моменты просто не учтены. Здесь и далее я постараюсь о них рассказать.

Итак, основой канвы в мире Blend4Web служит любая поверхность трехмерного объекта. Это означает, что вы можете вывести текстовую или иную информацию на канву (например, видео), а потом работать с этим объектом, как заблагорассудится. Здесь открываются широкие возможности для самых крутых эффектов. Ведь 3D модель с канвой ничем не отличается от любого иного трехмерного объекта — вращайте, масштабируйте, применяйте анимацию и физику. Вот пример работы с канвой, который приводят сами разработчики.

В своей игре для вывода Score я использовал простую прямоугольную плоскость, прикрепленную к углу экрана. Никаких особых настроек к объекту-носителю канвы применять не нужно. Материал создается самый обычный, зато текстура используется особая.

Подготовка поверхности объекта для вывода HTML5 Canvas:

  • Создать UV-развертку для той плоскости, где предполагается вывод канвы. Будьте внимательны и начинайте размещение своей сетки UV с верхней части текстуры. По некоторым причинам я первоначально размещал UV в нижней части текстуры и потерял немало времени, пытаясь понять, почему нет отрисовки.

143cd50dcac74fd3a1cee23f9adaa97d.jpg

  • Добавьте новую текстуру типа None в текстурный слот материала. Дайте ей нормальное название.
  • В параметрах текстуры установите тип источника (Source Type), как Canvas.


В принципе всё. Переходим к коду.

В примерах на сайте Blend4Web имеется готовый кусок кода, который выводит по-буквенно текст на канву. Именно его я и использовал в своем проекте. Привожу с некоторыми изменениями и дополнениями.

…
var m_tex = b4w.require("textures");
var m_scene = b4w.require("scenes");
...

// параметры печати текста
    var text = ["Hello”, "World!"];
    var MARGIN_LEFT = 250;
    var LINE_SPACING = 10;
    var MARGIN_TOP = 120;

// поиск объекта-носителя канвы
    var obj = m_scene.get_object_by_name("Object");
// поиск текстуры по имени
    var ctx_image = m_tex.get_canvas_ctx(obj, "tex_id");
    var font = ctx_image.font.split("px");
    var font_height = parseInt(font[0]);

//HTML5 Canvas функции и переменные
    ctx_image.fillStyle = "rgba(255,230,0,255)";
    ctx_image.clearRect(0,0,512,512);    
    ctx_image.font = "120px Arial";
    ctx_image.textAlign = "start";

//вывод текста
    for (var i = 0; i < text.length; i++)
        ctx_image.fillText(text[i], MARGIN_LEFT, Math.round(LINE_SPACING * font_height * i + MARGIN_TOP));

// обновление канвы
    m_tex.update_canvas_ctx(obj, "tex_id");

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

Волшебство HTML5 Canvas


Вы можете использовать не только системные шрифты, но и загружаемые. Для этого нужно добавить следующее описание в файл CSS:

@font-face {
    font-family: MyFont;
    src: url(fonts/MyFont.ttf);
}

В этом случае строка инициализации шрифта будет выглядеть так:

ctx_image.font = "120px MyFont";

Цвет шрифта в формате RGBA устанавливается строкой:

    ctx_image.fillStyle = "rgba(255,230,0,255)";

Вы можете изменить выравнивание текста внутри канвы. Например по центру:

ctx_image.textAlign = "center";

Есть некоторые эффекты с тенями:

    ctx_image.shadowOffsetX = 5;
    ctx_image.shadowOffsetY = 5;
    ctx_image.shadowBlur = 10;
    ctx_image.shadowColor = "rgba(255, 132, 0, 1)";

В итоге, немного поигравшись с возможностями HTML5 Canvas, я получил требуемый мне вывод Score.

49617437344245e3a20a69e1a57f0c63.jpg

Итак, традиционные выводы. Инструмент Viewport Alignment решает все проблемы по позиционированию элементов. Интеграция с HTML5 Canvas позволяет без проблем выводить информацию с широкими возможностями создания текстовых эффектов. 3D+канва — это вообще уникальная фишка для создания необычных трехмерных меню, окон и более сложных элементов.

А вот и ложка дёгтя (куда же без неё-то) — не хватает инструмента для удобной настройки вывода информации на HTML5 Canvas. При любом изменении параметров канвы приходится экспортировать проект, чтобы проверить результат. Это, конечно, отнимает немало времени на такого рода эксперименты. Но в целом, особых проблем в создании пользовательского UI для приложения Blend4Web не нашлось.

© Habrahabr.ru