创建一个互动的网上应用程序
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] 因应新的项目管理系统而改写文章。