Создание интерактивного веб-приложения
2014-05-08
С помощью движка Blend4Web можно создавать как простые, так и относительно сложные, насыщенные интерактивные веб-приложения. Рассмотрим создание простого приложения с использованием API Blend4Web, в котором реализуем взаимодействие с объектами 3D-сцены, например, анимируя объект при выделении его мышью.
Создание нового приложения
Для создания нового приложения следует воспользоваться менеджером проектов, входящим в состав Blend4Web SDK. Для этого требуется сначала запустить Blender (с установленным аддоном), а затем зайти на главную страницу SDK по адресу http://localhost:6687/. Там менеджер проектов будет доступен по соответствующей ссылке:
Далее следует выбрать Create New Project:
Далее нужно будет выбрать имя нового проекта, к примеру, "simple_app". В случае, если вдруг проект с таким именем уже существует, будет предложено ввести другое имя. Также можно ввести отображаемый в браузере заголовок приложения, например, "Interactive Web Application":
Остальные настройки оставим по умолчанию. После этого нажмем кнопку Create Project внизу данной страницы для создания приложения. Затем необходимо дождаться завершения и нажать Back to Projects:
Она вернет нас на страницу менеджера проектов, из которой можно открыть новое приложение по ссылке:
В результате мы увидим базовую сцену с простым кубиком:
Созданное нами приложение расположено внутри SDK по пути ./projects/simple_app/. Теперь, когда каркас проекта готов, можно приступать к созданию 3D-сцены и написанию логики приложения.
Подготовка и экспорт 3D-сцены
Blend-файл с базовой сценой находится в директории проекта: ./projects/simple_app/simple_app.blend. Откроем его в Блендере и вместо того, что есть по умолчанию, создадим в нем сцену с объектами, источником освещения и камерой.
Для каждого из "интерактивных" объектов сделаем простую анимацию перемещения, поворота (в режимах XYZ Euler либо Quaternion WXYZ) или масштабирования.
Также включим им опцию Selectable во вкладке Object->Selection and Outlining. Это сделает объекты доступными для выбора при клике по ним мышью.
Настроив по вкусу камеру, освещение и материалы объектов, экспортируем сцену через команду меню File -> Export -> Blend4Web (.json). Путь экспорта следует указать таким: ./projects/simple_app/assets/simple_app.json.
Добавление функционала
В директории проекта ./projects/simple_app/ в числе других будет находиться главный JS-файл приложения simple_app.js, содержащий шаблонный код. В нем и будем реализовывать простое взаимодействие пользователя с загруженной сценой.
Для реализации задуманного функционала нам понадобятся дополнительные модули:
- animation.js - предоставляет API для управления анимацией объектов
- container.js - методы, относящиеся к Canvas-элементу и его родительскому HTML-элементу
- mouse.js - содержит ряд полезных методов, относящихся к мыши
- scenes.js - API для доступа к объектам сцены
Добавим их подключение в самом начале скрипта к остальным модулям:
// import modules used by the app
var m_app = require("app");
var m_cfg = require("config");
var m_data = require("data");
var m_preloader = require("preloader");
var m_ver = require("version");
var m_anim = require("animation");
var m_cont = require("container");
var m_mouse = require("mouse");
var m_scenes = require("scenes");
В нашем примере по клику на объекте должна воспроизводиться его анимация, также будем и отменять анимацию у предыдущего выделенного объекта. Для этого в конец функции load_cb() добавим обработчик события "mousedown" для нажатий мышью по элементу Canvas. Также при необходимости можно добавить обработчик "touchstart" для нажатий на сенсорном экране:
function load_cb(data_id, success) {
...
var canvas_elem = m_cont.get_canvas();
canvas_elem.addEventListener("mousedown", main_canvas_click, false);
canvas_elem.addEventListener("touchstart", main_canvas_click, false);
}
Далее напишем соответствующую функцию-обработчик main_canvas_click():
function main_canvas_click(e) {
if (e.preventDefault)
e.preventDefault();
var x = m_mouse.get_coords_x(e);
var y = m_mouse.get_coords_y(e);
var obj = m_scenes.pick_object(x, y);
if (obj) {
if (_previous_selected_obj) {
m_anim.stop(_previous_selected_obj);
m_anim.set_frame(_previous_selected_obj, 0);
}
_previous_selected_obj = obj;
m_anim.apply_def(obj);
m_anim.play(obj);
}
}
Основная логика приложения содержится именно в ней. Алгоритм в общих чертах будет следующим:
1) Получение объекта сцены, который находился под курсором.
var x = m_mouse.get_coords_x(e);
var y = m_mouse.get_coords_y(e);
var obj = m_scenes.pick_object(x, y);
2) Отмена анимации у предыдущего выделенного объекта.
Остановка анимации:
m_anim.stop(_previous_selected_obj);
И выставление нулевого кадра, т.е. возвращение к первоначальному положению:
m_anim.set_frame(_previous_selected_obj, 0);
Для сохранения предыдущего объекта использована глобальная переменная _previous_selected_obj. Её нужно объявить где-либо, например, сразу после подключения модулей следующим образом:
var _previous_selected_obj = null;
3) Применение анимации к объекту.
Загрузка и расчет анимации, назначенной на объект в Blender'е:
m_anim.apply_def(obj);
Воспроизведение анимации:
m_anim.play(obj);
Приведём код получившегося приложения целиком:
"use strict"
// register the application module
b4w.register("simple_app_main", function(exports, require) {
// import modules used by the app
var m_app = require("app");
var m_cfg = require("config");
var m_data = require("data");
var m_preloader = require("preloader");
var m_ver = require("version");
var m_anim = require("animation");
var m_cont = require("container");
var m_mouse = require("mouse");
var m_scenes = require("scenes");
var _previous_selected_obj = null;
// detect application mode
var DEBUG = (m_ver.type() == "DEBUG");
// automatically detect assets path
var APP_ASSETS_PATH = m_cfg.get_assets_path("simple_app");
/**
* export the method to initialize the app (called at the bottom of this file)
*/
exports.init = function() {
m_app.init({
canvas_container_id: "main_canvas_container",
callback: init_cb,
show_fps: DEBUG,
console_verbose: DEBUG,
autoresize: true
});
}
/**
* callback executed when the app is initialized
*/
function init_cb(canvas_elem, success) {
if (!success) {
console.log("b4w init failure");
return;
}
m_preloader.create_preloader();
// ignore right-click on the canvas element
canvas_elem.oncontextmenu = function(e) {
e.preventDefault();
e.stopPropagation();
return false;
};
load();
}
/**
* load the scene data
*/
function load() {
m_data.load(APP_ASSETS_PATH + "simple_app.json", load_cb, preloader_cb);
}
/**
* update the app's preloader
*/
function preloader_cb(percentage) {
m_preloader.update_preloader(percentage);
}
/**
* callback executed when the scene data is loaded
*/
function load_cb(data_id, success) {
if (!success) {
console.log("b4w load failure");
return;
}
m_app.enable_camera_controls();
// place your code here
var canvas_elem = m_cont.get_canvas();
canvas_elem.addEventListener("mousedown", main_canvas_click, false);
canvas_elem.addEventListener("touchstart", main_canvas_click, false);
}
function main_canvas_click(e) {
if (e.preventDefault)
e.preventDefault();
var x = m_mouse.get_coords_x(e);
var y = m_mouse.get_coords_y(e);
var obj = m_scenes.pick_object(x, y);
if (obj) {
if (_previous_selected_obj) {
m_anim.stop(_previous_selected_obj);
m_anim.set_frame(_previous_selected_obj, 0);
}
_previous_selected_obj = obj;
m_anim.apply_def(obj);
m_anim.play(obj);
}
}
});
// import the app module and start the app by calling the init method
b4w.require("simple_app_main").init();
Веб-приложение, разобранное в статье, является простым, но в то же время интерактивным. Это минимальный пример того, что позволяет движок Blend4Web и его API.
Исходные файлы приложения и сцены находятся в составе бесплатного дистрибутива Blend4Web SDK по пути ./projects/simple_app/.
Ссылка на приложение в отдельном окне
Изменения
[2014-05-08] Изначальная публикация.
[2014-06-30] Уточнен текст об опции инициализации alpha.
[2014-07-07] Незначительные правки текста об исходных файлах приложения.
[2014-07-22] Изменен путь к приложению.
[2014-08-06] Обновлен код примера по причине изменения API получения объекта под курсором.
[2014-10-29] Обновлен текст статьи по причине изменения API.
[2014-11-28] Правки текста об исходных файлах приложения.
[2015-04-23] Правки текста об исходных файлах приложения.
[2015-05-08] Обновлен текст статьи по причине изменения API.
[2015-09-30] Небольшие изменения в статье.
[2015-10-02] Статья переписана с учетом системы управления проектами.
[2017-01-12] Исправлены некорректные/битые ссылки.
[2017-04-21] Обновлен текст статьи.