События

Вебмастерам: 3D-веб тремя способами

2014-08-01

В этой статье мы рассмотрим несколько способов размещения 3D контента, созданного с помощью Blend4Web, на веб-сайтах.

Способ 1: вставка HTML-файла

Одной из интересных особенностей Blend4Web является возможность экспортировать целые сцены из Blender'а в единственный HTML-файл, не имеющий внешних зависимостей. Такой файл представляет собой самодостаточную веб-страницу, открывающуюся стандартным браузером, которую можно распространять различными способами. В частности, ее можно разместить на веб-сайте внутри контейнера iframe, указав для него размеры и другие поддерживаемые свойства.

<!DOCTYPE html>
<html>
<head>
    <title>Apple</title>
</head>
<body>
    <iframe width="800" height="500" allowfullscreen src="/tutorials/examples/web_page_integration/apple.html"></iframe>
</body>
</html>

Основное преимущество этого способа заключается в его простоте. Пользователи, не имеющие опыта работы с Blend4Web, могут придерживаться следующего порядка действий:

  • загрузить и установить аддон для программы Blender (см. видео или раздел руководства пользователя);
  • экспортировать предварительно созданную сцену File > Export > Blend4Web (.html);
  • разместить полученный HTML-файл на сайте внутри контейнера iframe.

Способ 2: веб-плеер

Второй способ является вариантом первого - в результате на странице появляется вставка 3D контента с элементами управления.

Тем не менее, реализация вставки этим способом существенно отличается от предыдущего - вместо единственного HTML-файла здесь используется комбинация веб-плеера и загружаемого JSON-файла сцены.

<!DOCTYPE html>
<html>
<head>
    <title>Apple</title>
</head>
<body>
    <iframe width="800" height="500" allowfullscreen src="/apps/webplayer/webplayer.html?load=/tutorials/examples/web_page_integration/apple.json&show_fps"></iframe>
</body>
</html>

Директорию с файлами веб-плеера blend4web/deploy/apps/webplayer/ можно скопировать из дистрибутива Blend4Web SDK и разместить на сайте.

JSON-файлы сцены можно экспортировать аналогично HTML-файлам с помощью опции File > Export > Blend4Web (.json). Полученные файлы можно разместить на сайте и указать путь к ним (абсолютный или относительный) с помощью параметра веб-плеера load.

В этом примере помимо обязательного параметра load мы использовали необязательный - show_fps - для отображения счетчика кадров в секунду.

Подробнее с веб-плеером можно ознакомиться в соответствующем разделе руководства пользователя.

Примечание

Чтобы запускать веб-плеер из локальной файловой системы (т.е. без веб-сервера) необходимо настроить браузер для загрузки локальных ресурсов.

Хотя этот способ выглядит более сложным, чем предыдущий, он имеет ряд преимуществ:

  • компактный формат файлов сцены - загрузка происходит быстрее;
  • сцена загружается асинхронно, без блокировки загрузки всей страницы;
  • данные сцены хранятся отдельно от самого веб-плеера, что позволяет использовать их в других приложениях.

Способ 3: веб-приложение

Наконец, мы можем превратить саму веб-страницу в интерактивное 3D приложение! Продемонстрируем это на простом примере: разместим на странице кнопку, при нажатии на которую будет вопроизводиться интересный анимационный эффект.

В состав бесплатного дистрибутива также входит отдельное приложение, упрощающее изучение и отладку.

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

О том, как был создан сам анимационный эффект, будет рассказано в следующей статье, а сейчас посмотрим, как подключить его к странице. Как мы увидим, сделать это не сложнее, чем реализовать какой-нибудь эффект на jQuery или Flash.

Для начала подключим к странице скрипт движка b4w.min.js из дистрибутива Blend4Web. Код примера разместим в файле example.js. Таблицу стилей приложения будем хранить в файле example.css:

<link rel="stylesheet" type="text/css" href="example.css">

<script type="text/javascript" src="b4w.min.js"></script>
<script type="text/javascript" src="example.js"></script>

Разместим на странице контейнер для области отрисовки и кнопку для запуска эффекта. Для удобства обернем их элементом div#wrapper_container:

<div id="wrapper_container">
    <div id="canvas_cont"></div>
    <div id="run_button" class="ru"></div>
</div>

Рассмотрим таблицу стилей приложения:

#canvas_cont {
    position: absolute;
    width: 1200px;
    height: 1200px;
    bottom: -350px;
    pointer-events: none;
}

div#wrapper_container {
    position: relative;
}

@media screen and (min-width: 1000px) and (max-width: 1200px) {
    #canvas_cont {
        height: 1000px;
        width: 1000px;
    }
}

@media screen and (max-width: 1000px) {
    #canvas_cont {
        width: 100vw;
        height: 100vw;
        bottom: 0;
    }
}

div#run_button.ru,
div#run_button.en {
    width: 236px;
    height: 60px;
    margin: 0 auto;
    cursor: pointer;
    background-image: url(interface/button.png);
    background-size: 472px 120px;
}

div#run_button.en {
    background-position: -236px 0;
}

div#run_button.ru:hover {
    background-position: 0 -60px;
}

div#run_button.en:hover {
    background-position: -236px -60px;
}

Для контейнера области отрисовки зададим ширину, высоту и абсолютное позиционирование. Также сместим контейнер вниз, относительно родительского элемента на 350px. Выставим свойство pointer-events равным none. Данное свойство делает элемент прозрачным для событий мыши:

#canvas_cont {
    position: absolute;
    width: 1200px;
    height: 1200px;
    bottom: -350px;
    pointer-events: none;
}

Примечание

Более подробно ознакомиться со свойством pointer-events можно по адресу developer.mozilla.org/en-US/docs/Web/CSS/pointer-events.

Зададим относительное позиционирование для элемента div#wrapper_container. Это необходимо для того, чтобы дочерние элементы, имеюшие абсолютную позицию, оставались внутри родительского контейнера:

div#wrapper_container {
    position: relative;
}

Cкорректируем высоту, ширину и расположение области отрисовки для устройств с небольшими экранами:

@media screen and (min-width: 1000px) and (max-width: 1200px) {
    #canvas_cont {
        height: 1000px;
        width: 1000px;
    }
}

@media screen and (max-width: 1000px) {
    #canvas_cont {
        width: 100vw;
        height: 100vw;
        bottom: 0;
    }
}

Установим стили для кнопки запуска:

div#run_button.ru,
div#run_button.en {
    width: 236px;
    height: 60px;
    margin: 0 auto;
    cursor: pointer;
    background-image: url(interface/button.png);
    background-size: 472px 120px;
}

div#run_button.en {
    background-position: -236px 0;
}

div#run_button.ru:hover {
    background-position: 0 -60px;
}

div#run_button.en:hover {
    background-position: -236px -60px;
}

Теперь разберем скрипт example.js. Ниже целиком приведен его код:

"use strict";

b4w.register("example_main", function(exports, require) {

var m_anim   = require("animation");
var m_app    = require("app");
var m_data   = require("data");
var m_main   = require("main");
var m_scs    = require("scenes");
var m_sfx    = require("sfx");

exports.init = function() {
    m_app.init({
        canvas_container_id: "canvas_cont",
        callback: init_cb,
        physics_enabled: false,
        alpha: true,
        report_init_failure: false,
        media_auto_activation: false
    });
}

function init_cb(canvas_elem, success) {
    if (!success) {
        console.log("b4w init failure");
        return;
    }

    if (window.web_page_integration_dry_run)
        m_data.load("flying_letters.json", load_cb);
    else
        m_data.load("/tutorials/examples/web_page_integration/flying_letters.json", load_cb);

    resize();

    window.addEventListener("resize", resize);
}

function resize() {
    m_app.resize_to_container();
}

function load_cb(root) {
    var letters_arm = m_scs.get_object_by_name('beads_armature');

    m_anim.stop(letters_arm);

    run_button.addEventListener("mousedown", demo_link_click, false);
}

function demo_link_click(e) {
    m_data.activate_media();

    var letters_arm = m_scs.get_object_by_name('beads_armature');
    var spk = m_scs.get_object_by_name("Speaker");

    m_sfx.play_def(spk);
    m_anim.apply(letters_arm, "flying_letters");
    m_anim.play(letters_arm, letters_obj_cb);
}

function letters_obj_cb(obj) {
    m_anim.apply(obj, "flying_letters_idle");
    m_anim.set_behavior(obj, m_anim.AB_CYCLIC);
    m_anim.play(obj);
}

});

b4w.require("example_main").init();

Обратите внимание на параметры инициализации - прозрачность области отрисовки alpha включена:

exports.init = function() {
    m_app.init({
        canvas_container_id: "canvas_cont",
        callback: init_cb,
        physics_enabled: false,
        alpha: true,
        report_init_failure: false,
        media_auto_activation: false
    });
}

Загрузим сцену:

    if (window.web_page_integration_dry_run)
        m_data.load("flying_letters.json", load_cb);
    else
        m_data.load("/tutorials/examples/web_page_integration/flying_letters.json", load_cb);

Примечание

Проверка переменной web_page_integration_dry_run выполняется для указания пути к JSON файлу в отладочном приложении. Т. е. в нем путь к JSON файлу - "flying_letters.json", а на текущей странице - "/tutorials/examples/web_page_integration/flying_letters.json".

Ниже приводится пример добавления переменной web_page_integration_dry_run в html файл:

    <script type="text/javascript">
        window.web_page_integration_dry_run = true;
    </script>

Добавим обработчик событий на измение размеров окна браузера. Затем принудительно вызовем функцию resize():

    window.addEventListener("resize", resize);

    resize();

В функция resize() используется метод resize_to_container(), который устанавливает высоту и ширину области отрисовки как и родительского контейнера:

function resize() {
    m_app.resize_to_container();
}

После загрузки сцены, вызывается функция load_cb(). В ней мы останавливаем анимацию - потому что мы установили ее на автозапуск в Blender'е - и привязываем к элементу #run_button событие mousedown:

    var letters_arm = m_scs.get_object_by_name('beads_armature');

    m_anim.stop(letters_arm);

    run_button.addEventListener("mousedown", demo_link_click, false);

При клике по элементу #run_button вызывается функция demo_link_click(). В ней мы запустим анимацию полета шаров и звук нажатия кнопки:

    m_data.activate_media();

    var letters_arm = m_scs.get_object_by_name('beads_armature');
    var spk = m_scs.get_object_by_name("Speaker");

    m_sfx.play_def(spk);
    m_anim.apply(letters_arm, "flying_letters");
    m_anim.play(letters_arm, letters_obj_cb);

После окончания анимации полета вызывается функция letters_obj_cb(). В ней мы запустим циклическую анимацию, чтобы шары покачивались на месте:

    m_anim.apply(obj, "flying_letters_idle");
    m_anim.set_behavior(obj, m_anim.AB_CYCLIC);
    m_anim.play(obj);

Вот и все!

Выводы

Технология WebGL предоставляет уникальную возможность бесшовной интеграции интерактивного 3D контента с другими веб-технологиями. С помощью Blend4Web можно относительно легко создать такой контент в популярной программе Blender, разместить его на веб-страницах и объединить логикой с любыми HTML элементами.

Изменения

[2014-08-01] Изначальная публикация.

[2014-10-22] Изменены пути к файлам сцен.

[2014-10-30] Исправлены ссылки к веб-плееру в связи с изменением имени файла. Добавлен атрибут allowfullscreen. Опущен устаревший параметр bg.

[2014-12-03] Добавлен звук для кнопки.

[2015-04-23] Изменен путь к исходникам веб-плеера на GitHub. Изменены имена переменных и анимаций. Опущен параметр deferred_rendering и context_antialias в функции m_app.init().

[2015-05-15] Добавлено описание стилей приложения. Логика изменения размеров области отрисовки перенесена из скрипта в таблицу стилей. Добавлена ссылка на отладочное приложение. Добавлено описание функции resize()

[2015-12-10] Удален модуль app.js

[2017-01-12] Небольшие правки текста.