日志

网站主管们! 3招 进到 3D Web

2014-08-01

在这篇文章中,我们将学习如何将 Blend4Web 创建的 3D 内容放置到网站。

方法 1︰嵌入 HTML 文件

将整个场景从 Blender 导出到单独的 HTML 文件,而无需依赖外部的方法,是 Blend4Web 相当令人兴 奋的特点之一。此类文件是全功能的Web网页,它可通过标准的浏览器打开并用任何方式分享。您可以 设置尺寸和其他受支持的属性,利用 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:网络播放器 Web Player

第二种方式是第一种的替代版本。其结果是一个嵌入 3D 内容与控制组件,被显示在页面上。

然而这种实现嵌入与前一个本质上不同:不是单一的 HTML 文件用于网络播放器和加载的 JSON 场景文件组合。

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

您可以从 from the Blend4Web SDK 发行的目录中,复制包含 web player 文件 deploy/apps/webplayer 并将 其部署在 web 站点上。

JSON 场景文件导出可以利用与 HTML 文件相同的方式 File > Export > Blend4Web (.json) 选项。 您可在您的 web 站点上指定路径 (绝对或相对) 放置生成的文件和 加载 web player 参数.

在此示例中除了强制性 加载 参数外,我们用另一种选项 ︰show_fps 用于显示帧速率。

你可以通过阅读相应的 用户手册,自己熟悉 web player。

注意

若要从本地文件系统运行 web player(即使没有 web server) 您需要设置您的浏览器加载本地资源

虽然此方法看起来比第一个复杂点,但提供一堆好处︰

  • 场景文件格式是简洁的 - 因此他们的加载速度更快;
  • 场景是异步加载,不会阻塞加载的页面本身;
  • 场景数据分散存储于 web player,来允许他们使用在其他应用程序中。

方法 3: Web 应用程序

最后我们可以将 web 页本身转换成一个交互式的 3D 应用程序!让我们用一个简单的例子证明︰我们放置一个按钮,它被按下时,会在此页播放有趣的动画效果。

免费的 Blend4Web SDK 发行版包含 独立的应用程序 ,來简化学习和调试。

瞧:页面内容不仅可以通过无形的 画布查看, 而背后半透明的 3D 对象移动时亦有高光动态的变化。

我们将在下一篇文章中,谈论这个动画效果如何创建。现在让我们瞧瞧它如何挂到到该页上。我们将见到 ,做类似的东西,不比在 jQuery 或 Flash 里边复杂

首先我们将链接从 Blend4Web 发行的脚本引擎 (b4w.min.js) 。 我们会在 example.js 文件中编写示例代 码。 我们将在 example.css 文件中编写 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>

然后我们在网页里替选 渲染区域canvas_cont 和 效果发射按钮run_button 准备一个容器。将所有的元素包裹到 父级容器wrapper_container 中,以简化内容:

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

了解 CSS 应用程序:

#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;
}

设置渲染区域的 宽width 高height 和 位置position。相对于之于父级元素,下移容器 bottom 350px像素. 设置 事件点pointer-events 属性为 无none. 该属性允许元素不接收 悬停hover / 点击click 事件, 取而代之的,事件将发生在它背后的任何状况下 ︰

#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;
}

修正一点宽度、 高度、 位置,来符合较小屏幕的设备 ︰

@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;
    }
}

设置了启动按钮的 CSS 样式:

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();

注意 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_runhtml 文件的示例 ︰

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

添加浏览器窗口调整大小事件的监听器 window.addEventListener。然后调用 resize() 函数使它生效︰

    window.addEventListener("resize", resize);

    resize();

如他的父级容器, resize()函数使用 resize_to_container() 的方法,设置当前元素的宽度和高度:

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

场景加载,执行 load_cb() 函数后。在它里边我们停止动画,因为我们已经为它在 Blender 里启用了 auto-run自动运行 模式。然后我们将 mousedown 事件附加到 #run_button 元素里 ︰

    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 给了一个独一无二的机会,无缝的与其他 web 技术集成交互式 3D 内容。在 Blender 里您可以 轻松地创建此类内容给 Blend4Web 、 部署在 web 页里和从逻辑上,它将与任何 HTML 元素相结合。

更新日志

[2014-08-01] 首次发布。

[2014-10-22] 更新文件路径

[2014-10-30] 更新 web player 的链接。添加 allowfullscreen 属性。删除过时的 bg 参数。

[2014-12-03] 添加声音

[2015-04-23] Webplayer 源文件的路径更新。更新变量和动画名称。从 m_app.init() 函数中,删除 deferred_renderingcontext_antialias 参数。

[2015-05-15] 添加 CSS 样式描述。把渲染区域大小调整逻辑,从脚本替换到 CSS 数据表中。替独立的应用程序添加链 接。添加了 resize() function 功能描述。

[2015-12-10] 删除 app.js 模块。

[2016-02-11] 修正 css。