日志

创建一个互动的网上应用程序

2014-05-08

Blend4Web 使得创建简易,和较为复杂的,丰富互动的互联网应用程序,成为可能。 让我们瞧瞧如何用 Blend4Web API 创建简易的应用程序。在此应用程序里我们将实现与3D对象互动,举例来说,用鼠标点击使对象活动。

创建一个新的应用程序

要创建新的应用程序,第一,可以使用 Project Manager 项目管理 ,它包括在 Blend4Web SDK 里。 它可通过 SDK 主页面链接启动。 如果已使用 local development server ,此页面可经由下列地址访问: http://localhost:6687/

接着我们应该点击 Projects[+new] 链接。

然后在字段填入如下图,我们替新项目指定的名称(例如"simple_app"),接着吩咐 Project Manager 去创建所有基本还没有完全运行的应用程序所需要的资源和文件。简单起见,这些也将放置于单一个目录中。此外,我们可以指定应用程序标题,它将被显示在浏览器里。(例如"Interactive Web Application")

接着无须其他动作, 点击 Create创建应用程序。然后我们可以通过 Project Manager page项目管理页面 查看应用程序主 HTML 文件:

此后,我们将看到基础场景中的一个简单立方体:

通常,一个新的应用程序会放在 SDK 的 ./apps_dev/PROJECT_NAME 专案名称/ 文件夹里。文件夹名为 ./apps_dev/simple_app 简易应用程序/ 。 这是项目目录内主要的应用程序文件:

- simple_app.html - 主要的 HTML 档案

- simple_app.js - JavaScript Java描述语言 档案 ,其中在应用程序里包含了逻辑

- simple_app.css - CSS 档案

- simple_app.blend - 主要 Blend 档案

- simple_app.json/simple_app.bin - 输出的 3D 场景档案

现在,应用程序的骨干已准备就绪,我们可以开始创建一个 3D 场景,和着手编写逻辑。

预备和导出3D场景

我们会在Blender场景中创建几个对象,光源和摄像机。



我们将对每一个互动的对象,做一点简单的动作,旋转 (在 XYZ Euler 欧拉角度 or Quaternion WXYZ 四元数移动 方式) 和缩放。



我们也启用 Object对象->Selection选择 和 Outlining大纲 标签下的 Selectable 可选的 复选框。这让对象可经由鼠标点击选取。



经由您的喜好,在设置了摄像机,灯光和对象材质后,我们将经由 File文件-> Export导出 -> Blend4Web (.json) 菜单选项输出场景。导出路径已经根据项目目录予以修正。

应用程序模板

应用程序逻辑已经包含在 simple_app.js 脚本中。在项目创建后会立即出现一些样板代码。该代码足以载入场景并提供基本的相机控制。

simple_app.js 档的源代码:

"use strict"

// register the application module
b4w.register("simple_app", function(exports, require) {

// import modules used by the app
var m_app       = require("app");
var m_data      = require("data");

/**
 * 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: true,
        console_verbose: true,
        autoresize: true
    });
}

/**
 * callback executed when the app is initizalized
 */
function init_cb(canvas_elem, success) {

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

    load();
}

/**
 * load the scene data
 */
function load() {
    m_data.load("simple_app.json", load_cb);
}

/**
 * callback executed when the scene is loaded
 */
function load_cb(data_id) {
    m_app.enable_controls();
    m_app.enable_camera_controls();

    // place your code here

}


});

// import the app module and start the app by calling the init method
b4w.require("simple_app").init();

咱们来看看这个脚本的详细讯息:

a) 注册应用模块

一个典型的 Blend4Web 应用具有模块化设计,其中应用程序脚本被组织成模块,并通过引擎注册:

// register the application module
b4w.register("simple_app", function(exports, require) {...}

这里有两个很重要的参数:

- exports - 全局队列;供应从外部访问该模块的功能

- require要求 - 其他加载模块的功能


b) 加载必要的引擎模块

此模块默认加载:

b4w.register("simple_app", function(exports, require) {
    ...
// import modules used by the app
var m_app       = require("app");
var m_data      = require("data");
    ...
});

- app.js - 用以简化应用程序的初始化

- data.js - 用来加载3D场景数据的 API


c) 初始化应用程序

应用程序已被 exports.init() 函数初始化。此功能已经由"exports 输出"数组宣告,将提供外部使用:

b4w.register("simple_app", function(exports, require) {
    ...
/**
 * 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: true,
        console_verbose: true,
        autoresize: true
    });
}
    ...
});

// import the app module and start the app by calling the init method
b4w.require("simple_app").init();

m_app.init() 函数在此将用来创建 Canvas HTML 元素和初始化 WebGL.它需要很多参数:

- canvas_container_id - HTML 元素 里的身份代码,该Canvas要素将被创建;这个有着"main_canvas_container "身份代码的元素呈现在主 HTML 文件文件(simple_app.html)默认情况下使用

- callback - 在 app 初始化后调用函数

- show_fps - 是否显示帧速率

- console_verbose - 是否在浏览器仪表盘显示除错信息

- autoresize - 是否根据浏览器窗口自动调整 Canvas 组件的尺寸

Note

在网页载入后 exports.init() 函数会被异步呼叫。m_app.init() 函数会将初始化阶段分配给 window.onload 事件以确保整个DOM树可用。


d) 加载场景

初始化完成后,init_cb() 会被呼叫。这个函数被指定为上述的callback回调参数。即使场景尚未装载,它里边已经可以进行一些预备动作。

/**
 * callback executed when the app is initizalized
 */
function init_cb(canvas_elem, success) {

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

    load();
}

功能参数:

- canvas_elem - 创建 Canvas HTML 元素

- success - 标志显示 Canvas 已经成功创建和初始化

这个场景已经由 load() 函数加载。

/**
 * load the scene data
 */
function load() {
    m_data.load("simple_app.json", load_cb);
}

在此,simple_app.json 场景已经由data.js 模块加载。第一项参数是关于HTML 的 JSON 文文件路径,第二项是 3D 场景加载后调用的功能

调用load_cb() 函数,代表我们跨过 initialization初始化 /loading 加载 阶段和启动应用程序。它也开始渲染场景。默认状态下,此时该应用程序允许用户输入和控制摄像机:

/**
 * callback executed when the scene is loaded
 */
function load_cb(data_id) {
    m_app.enable_controls();
    m_app.enable_camera_controls();

    // place your code here

}

这是我们所有最早加载的场景数据。因此这是一个合适准备和初始化所有场景相关东西的地点。


添加功能

现在应用程序的骨干准备完成后,咱们可以和场景里的对象实施简单的互动了。

我们需要几个模块来实现这个功能:

- animation.js - 提供 API 来控制对象动画

- scenes.js - 用来访问场景对象的API

在我们的代码里导入它:

// import modules used by the app
var m_anim      = require("animation");
var m_app       = require("app");
var m_data      = require("data");
var m_scenes    = require("scenes");

在我们的例子里,动画应该以单击该对象来播放。我们亦将取消先前选取对象的动画。就在 init_cb() 函式里,我们会创建"mousedown" 事件,马上在 app 初始化后回调:

function init_cb(canvas_elem, success) {
    ...
    canvas_elem.addEventListener("mousedown", main_canvas_click, false);
    ...
}

function main_canvas_click(e) {
    if (e.preventDefault)
        e.preventDefault();

    var x = e.clientX;
    var y = e.clientY;

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

主逻辑包含在 main_canvas_click() 函数中。总之,该算法如下:

1) 获取光标下的物件。

var x = e.clientX;
var y = e.clientY;

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 全局变量是用来保存先前的对象对象

3) 应用动画对象。

加载和预先计算被加在Blender对象上的动画:

m_anim.apply_def(obj);

动画播放:

m_anim.play(obj);

咱们来概观最后的应用程序代码:

"use strict"

// register the application module
b4w.register("simple_app", function(exports, require) {

// import modules used by the app
var m_anim      = require("animation");
var m_app       = require("app");
var m_data      = require("data");
var m_scenes    = require("scenes");

var _previous_selected_obj = null;

/**
 * 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: true,
        console_verbose: true,
        autoresize: true
    });
}

/**
 * callback executed when the app is initizalized
 */
function init_cb(canvas_elem, success) {

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

    canvas_elem.addEventListener("mousedown", main_canvas_click, false);

    load();
}

/**
 * load the scene data
 */
function load() {
    m_data.load("simple_app.json", load_cb);
}

/**
 * callback executed when the scene is loaded
 */
function load_cb(data_id) {
    m_app.enable_controls();
    m_app.enable_camera_controls();

    // place your code here

}

function main_canvas_click(e) {
    if (e.preventDefault)
        e.preventDefault();

    var x = e.clientX;
    var y = e.clientY;

    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").init();


此篇文章中描述的 Web 应用程序描述很简单,但仍是互动的。这是展现 Blend4Web 和 API 可能性的一个最小例子。

应用程序的源文件和场景档放置在免费的 Blend4Web SDK 位置下: ./deploy/tutorials/examples/interactive_web_application/.

链接到独立的应用程序

更新日志

[2014-05-08] 初始发行。

[2014-06-30] 优化 alpha屏蔽 initialization option初始化选项内文。

[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] 因应新的项目管理系统而改写文章。

评论
注册登录 后发送信息。