TWaver MONO Design
为了让开发者快速理解mono的开发方法,下面是一个简单的例子,通过几分钟即可完成。之后,您可以继续深入学习mono详细的开发方法。通过这个简单的例子,您可以体验使用mono进行开发是多么方便和快捷。
1.创建HTML文件
创建一个最简单的mono程序,只需mono.js这一个库文件即可。用编辑工具创建一个test.html文件,内容如下:
<html> <head> <meta charset="utf-8"/> <title>Hello MONO</title> <script type="text/javascript" src = "mono.js"></script> <script type="text/javascript"> //your code here </script> </head> <body onload = "load()"> <div id = "mainDiv"> <canvas id="myCanvas" / </div> </body> </html>
以上HTML代码创建了一个空白页面,并在页面加载结束后调用load函数,在load函数中填写代码即可。其中mono.js包通过一个script标签进行引入。浏览器访问该页面,会显示一个空白页面。
接下来,我们在load函数中创建一个3D场景。在load函数中,我们先创建一个3D的基本场景。一个简单的3D场景,需要有一些基本的元素,包括数据容器、3D视图、镜头、灯光、3D物体等。下文中我们会逐个逐步详细说明。
2.创建DataBox
在mono中,所有的3D物体都需要放入一个DataBox容器进行统一管理。这一设计方式和TWaver的2D产品(如TWaver Java、TWaver HTML5等)保持一致,也是基本的MVC设计准则。Mono中,数据放入数据容器进行管理(DataBox代表MVC中的Model层,与TWaver 2D中DataBox类似),3D的数据绘制和展示放在Network中管理(Network代表MVC中的View层,与TWaver 2D中的Network类似)。
需要留意的是,这里的DataBox和Network都是mono中的类,位于mono.*包下,和TWaver HTML5中的twaver.*包不同,两者代码也是完全分离的。
所以,创建3D场景首先需要创建一个DataBox容器,用来容纳3D场景中的各种物体。代码非常简单,直接new一个mono.DataBox即可:
var box = new mono.DataBox();
3.创建镜头
有了DataBox后,需要创建一个Network对象来显示3D场景。在创建Network之前,我们首先需要创建一个镜头对象来构造Network。
镜头(mono.Camera)是一个代表用户第一视角的对象,它类似我们的眼睛。和2D不同,3D世界中我们看到的场景会随着我们的“眼睛”的位置的不同而变化。物体的远近、大小、角度、光照等,都与镜头有直接的关系,因此每一个Network必须有一个镜头与之对应。
镜头有许多参数,主要是对镜头透视的定义。此处先不展开介绍,开发时使用最常见的参数即可:
var camera = new mono.PerspectiveCamera(); camera.setPosition(50,80,100);
上面代码中,第一句话表示创建镜头对象,第二句话设置镜头的空间位置(x、y、z)。
4.创建Network
Network是mono中3D的绘制“画布”,它负责把DataBox中的3D数据通过WebGL技术渲染绘制出来,并接受用户的各种交互(鼠标、键盘、触控等)。
var network= new mono.Network3D(box, camera, myCanvas);
上面的代码创建了一个Network对象。其中第一个参数是前面创建的DataBox对象,第二个参数是前面创建的镜头对象,第三个参数是HTML中定义的canvas对象的id值,也就是这句中定义的canvas对象:
<canvas id="myCanvas"/>
创建Network后,一般还需要设置一些交互模式,否则这个Network只能显示3D场景,而不能响应鼠标等交互动作(如旋转、缩放等)。和TWaver 2D中类似,Network的交互模式都被封装在各种Interaction中,直接创建并设置给Network即可。这里我们给Network设置了一个默认的交互模式:mono.DefaultInteraction。它为Network提供了最常用、基本的交互模式,包括鼠标和触控的旋转、缩放等操作。
var interaction = new mono.DefaultInteraction(network); interaction.zoomSpeed = 30; network.setInteractions([interaction]);
上面代码先创建了一个默认Interaction,并为它设置了缩放操作的相应速度(如鼠标滚轮),最后放在一个数组中设置给Network。Network可以接受一个Interaction数组,这些Interaction可以通过自由组合添加到Network中,这些Interaction会同时生效,以满足各种不同的交互要求。
例如,可以在数组中再添加EditInteraction、SelectionInteraction等,就可以增加编辑、选中等交互功能。
接下来,我们添加一行代码,让Network始终保持全屏充满页面空间,即使改变页面窗口大小也会保持这个效果,用户视觉体验会更加直观,使用也比较方便。
mono.Utils.autoAdjustNetworkBounds(network,document.documentElement,'clientWidth','clientHeight');
以上就完成了Network的基本设置。
5.创建灯光
一般而言,在3D场景中模拟真实世界的场景,光照是一个非常重要的元素。在一个完全没有光照的3D场景中,所有物体都是黑色的,就和现实世界中一个完全黑暗的房间一样。为了让物体反射光线到我们的眼睛里,除了需要给物体设置材质之外,首先要给场景添加光源。
在mono中,有多种类型的光源可供选择。最常见的有两个:环境光(mono.AmbientLight)和点光源(mono.PointLight)。环境光类似现实世界中漫反射的环境光,它没有固定统一的方向,所有物体的所有面都会接收到环境光发来的光源。点光源是一个发光点,以其位置为中心向四周发射光照。
一般3D场景中,我们可以同时使用这两种光源,来模拟真实场景。例如环境光模拟现实世界环境光,点光源模拟现实中的太阳光或室内的灯光。如果需要,还可以设置多个点光源,来模拟多个位置的灯光。
光照最主要的属性有光的颜色、强度等。点光源还需要设置其位置。
光源对象和3D物体对象类似,也要放入DataBox中。下面代码创建了一个点光源和环境光,并加入DataBox中:
//create point light. var pointLight = new mono.PointLight(0xFFFFFF,1); pointLight.setPosition(10000,10000,10000); box.add(pointLight); //create ambient light. box.add(new mono.AmbientLight(0x888888));
6.创建3D物体
通过以上的代码,我们就搭建好了3D场景,但尚未放入任何3D物体。最后,我们来创建一个简单的3D立方体,并放入场景中。Mono中提供了很多基本3D形状,如立方体(mono.Cube)、圆柱体(mono.Cylinder)等等。每个物体可以设置其大小、位置、旋转角度、缩放比例、材质等属性。更多物体类型和属性的介绍请看后续章节及apidoc。
在这里,我们创建一个长宽高分别为25、25、25的立方体,并设置其位置(x、y、z)为55、50、55。然后设置其材质图片、材质类型等属性。最后将其置入DataBox中进行显示。代码如下:
var node=new mono.Cube(25,25,25); node.setPosition(55, 50, 55); node.setStyle('m.texture.image','../images/fence.png').setStyle('m.type','phong'); box.add(node);
请注意,上述代码中,’m.texture.image’属性是材质图片,可传入png、jpg等图片的url地址;’m.type’是材质的类型,分为’basic’和’phong’两种。其中,’phong’类型支持高光光照效果,而’basic’类型不支持光照效果。
7.完整代码
以上介绍的完整代码如下:
<!DOCTYPE html> <html> <head> <title>Hello MONO</title> <script type="text/javascript" src = "mono.js"></script> <script type="text/javascript"> function load(){ var box = new mono.DataBox(); var camera = new mono.PerspectiveCamera(30, 1.5, 0.1, 10000); camera.setPosition(50,80,100); var network= new mono.Network3D(box, camera, myCanvas); var interaction = new mono.DefaultInteraction(network); interaction.zoomSpeed = 30; network.setInteractions([interaction]); mono.Utils.autoAdjustNetworkBounds(network,document.documentElement,'clientWidth','clientHeight'); var pointLight = new mono.PointLight(0xFFFFFF,1); pointLight.setPosition(10000,10000,10000); box.add(pointLight); box.add(new mono.AmbientLight(0x888888)); var node=new mono.Cylinder(25,25,25); node.setPosition(55, 50, 55); node.setStyle('m.texture.image','../images/fence.png').setStyle('m.type','phong'); box.add(node); } </script> </head> <body onload = 'load()'> <div id = "mainDiv"> <canvas id="myCanvas"/> </div> </body> </html>