转载

基于HTML5 WebGL实现3D飞机叶轮旋转

在上一篇《 基于HT for Web矢量实现2D叶轮旋转 》中讲述了叶轮旋转在 2D 拓扑 上的应用,今天我们就来讲讲叶轮旋转在 3D 上的应用。

3D拓扑 上可以创建各种各样的图元,在 HT for Web 系统中提供了一些常规的 3D模型 ,但是对于那些比较复杂的模型,比如汽车、人物等模型就无能为力了,那再项目中需要用到这样的模型该肿么办呢?这时候就需要借助专业的3ds Max工具来建模了,然后通过3ds Max工具将模型导出成obj文件,然后再项目中引用导出的obj文件,这样就能成功的使用上复杂的图元了。

在《 HT图形组件设计之道(四) 》一文中有提及 HT for Web 引入obj文件的介绍,在这里我就不做重复介绍了,我们先来看看今天作为演示的Demo模型长什么样:

http://www.hightopo.com/guide/guide/plugin/obj/ht-obj-guide.html

基于HTML5 WebGL实现3D飞机叶轮旋转

嘿嘿,是不是感觉今天的模型有些大材小用了,没办法,怪只怪自己不懂3ds Max工具,只能先用这个大家熟悉的模型来做Demo演示了。

首先我们需要有3ds Max工具将模型导出成obj及mtl文件,然后调用 HT for Web 的ht.Default.loadObj()方法读取并解析模型文件,在解析完成后,通过调用ht.Default.setShape3dModel()方法将模型注册到系统中,如此在后续的代码中就能够应用到该模型了,模型文件的读取及注册具体代码如下:

ht.Default.loadObj('plane.obj', 'plane.mtl', {       center: true,  r3: [0, -Math.PI/2, 0], // make plane face right  s3: [0.15, 0.15, 0.15], // make plane smaller  finishFunc: function(modelMap, array, rawS3){   if(modelMap){      ht.Default.setShape3dModel('plane', array);    var plane = new ht.Node();    plane.s3(rawS3);    plane.s({     'shape3d': 'plane',     'shape3d.scaleable': false,     'wf.visible': true,     'wf.color': 'white',     'wf.short': true    });    dataModel.add(plane);   }  } }); 

注册完3D模型后,我们马上创建了一个3D图元,并将其添加到了 dataModel 容器中,这时我们需要一个3D拓扑来显示这个3D图元,具体的创建代码如下:

var dataModel = new ht.DataModel(); var g3d = new ht.graph3d.Graph3dView(dataModel); g3d.setEye(200, 50, 300); g3d.setDashDisabled(false); g3d.getView().style.background = '#4C7BBB'; g3d.addToDOM();

3D拓扑 上做了些简单的属性设置,让 拓扑 看起来舒服些,如此我们就可以看到我们创建出来的飞机模型到底长什么样了

基于HTML5 WebGL实现3D飞机叶轮旋转

怎么样,创建一个复杂模型好像并没有想象中的复杂(复杂的东西都让美工做完了)。

我们仔细观察飞机会发现,飞机前面的螺旋桨颜色和机身一样,一眼看去不太容易注意到它的存在,那能否将其颜色改掉呢?我们可以查看下mtl文件,看飞机的螺旋桨是否分离机身独立成一个材质,mtl文件的内容如下:

newmtl body  Ns 10.0000  Ni 1.5000  d 1.0000  Tr 0.0000  Tf 1.0000 1.0000 1.0000   illum 2  Ka 0.3608 0.4353 0.2549  Kd 0.3608 0.4353 0.2549  Ks 0.0000 0.0000 0.0000  Ke 0.0000 0.0000 0.0000 newmtl propeller  Ns 10.0000  Ni 1.5000  d 1.0000  Tr 0.0000  Tf 1.0000 1.0000 1.0000   illum 2  Ka 0.3608 0.4353 0.2549  Kd 0.3608 0.4353 0.2549  Ks 0.0000 0.0000 0.0000  Ke 0.0000 0.0000 0.0000 

正如我们所想,飞机模型的机身和螺旋桨是分开了两个独立的材质,并将螺旋桨的材质名字定义为propeller,因此我们可以独立控制机身及螺旋桨,那么我们就来修改下螺旋桨的颜色吧,在loadObj()方法中的finishFunc回调函数中添加上如下代码即可:

modelMap.propeller.s3 = [1, 1.2, 1.2]; modelMap.propeller.color = ‘yellow';

在代码中,我们不仅改变了螺旋桨的颜色,我们还对螺旋桨做了缩放处理,令螺旋桨的宽度和长度变大一点。

基于HTML5 WebGL实现3D飞机叶轮旋转

到这里,模型就算完成了,接下来要做的就是让螺旋桨动起来,和2D叶轮旋转类似,在3D模型上也可以做数据绑定,要想让螺旋桨旋转起来,我们就需要设置螺旋桨的rotation属性,和3D上的图元不同的是,设置3D图元的rotation属性需要设置一个数组,定义3D上三个方向的旋转值。

我们先来尝试下让螺旋桨沿着x轴旋转45度试下:

modelMap.propeller.r3 = [Math.PI / 4, 0, 0];

基于HTML5 WebGL实现3D飞机叶轮旋转

果然可以,那么接下来我们就可以为螺旋桨的rotation属性做 数据绑定 的处理了:

modelMap.propeller.r3 = {     func: function(data){         return [data.a('angle'), 0, 0];     } };

我们将螺旋桨的x轴上的旋转角度绑定到图元的angle自定义属性上,我们可以通过改变angle属性值令螺旋桨沿着x轴转动起来,那么接下来我们就通过定时器来动态改变angle属性吧,看看螺旋桨是不是真的可以动起来:

window.setInterval(function() {     var rotation = plane.a('angle') + Math.PI / 10;     if (rotation > Math.PI * 2) {         rotation -= Math.PI * 2;     }     plane.a('angle', rotation); }, 40);

螺旋桨果然动起来了,这个定时器让螺旋桨做匀速运动,但是飞机的螺旋桨在起飞和降落的时候其旋转速度都不是匀速,我们要模拟飞机起飞和降落时螺旋桨的旋转速度该如何处理呢?这个时候我们可以考虑用 HT for Web 中的 动画 来解决这个问题,关于动画的内容由于比较复杂,在这里就不深入探讨,等以后有机会再和大家分享动画的相关内容,今天就先讲诉下动画的基本用法,简单实现螺旋桨模拟起飞和降落的效果,具体的代码如下:

var params = {  delay: 1500,  duration: 20000,  easing: function(t){   return (t *= 2) < 1 ? 0.5 * t * t : 0.5 * (1 - (--t) * (t - 2));  },  action: function(v, t){   plane.a('angle', v*Math.PI*120);  },  finishFunc: function(){   ht.Default.startAnim(params);  } }; ht.Default.startAnim(params); 

我们来分析下代码:

1. delay属性:定义动画播放前的停顿时间;

2. duration属性:定义动画持续时间;

3. easing函数:定义动画缓动函数;

4. action函数:action函数必须提供,实现动画过程中的属性变化,在这里设置angle属性;

5. finishFunc函数:动画结束后调用的函数,在这里又启动了动画,让螺旋桨不断的旋转。

运行代码,你会发现螺旋桨在1.5秒后进入旋转状态,并且旋转速度由慢变快,再变慢直至停止,然后再过1.5秒后继续旋转,如此周而复始。

好了,今天的内容到这里就结束了,整个Demo的运行效果可以通过下面的视频查看,最后再附上本次Demo的所有代码。

http://v.youku.com/v_show/id_XMTI5NDI5MzYyOA==.html

<!DOCTYPE html> <html>  <head>   <title>HT for Web - Plane</title>   <meta charset="UTF-8" name="viewport" content="user-scalable=yes, width=600">   <script src="../../../build/ht-debug.js"></script>   <script src="../../../build/ht-obj-debug.js"></script>   <script>    function init(){     var dataModel = new ht.DataModel();     var g3d = new ht.graph3d.Graph3dView(dataModel);     g3d.setEye(200, 50, 300);     g3d.setDashDisabled(false);     g3d.getView().style.background = '#4C7BBB';     g3d.addToDOM();     ht.Default.loadObj('plane.obj', 'plane.mtl', {      center: true,      r3: [0, -Math.PI/2, 0], // make plane face right      s3: [0.15, 0.15, 0.15], // make plane smaller      finishFunc: function(modelMap, array, rawS3){       if(modelMap){        modelMap.propeller.r3 = {         func: function(data){          return [data.a('angle'), 0, 0];         }        };        // make propeller a litter bigger        modelMap.propeller.s3 = [1, 1.2, 1.2];        modelMap.propeller.color = 'yellow';        ht.Default.setShape3dModel('plane', array);        var plane = new ht.Node();        plane.s3(rawS3);        plane.s({         'shape3d': 'plane',         'shape3d.scaleable': false,         'wf.visible': true,         'wf.color': 'white',         'wf.short': true        });        dataModel.add(plane);        var params = {         delay: 1500,         duration: 20000,         easing: function(t){          return (t *= 2) < 1 ? 0.5 * t * t : 0.5 * (1 - (--t) * (t - 2));         },         action: function(v, t){          plane.a('angle', v*Math.PI*120);         },         finishFunc: function(){          ht.Default.startAnim(params);         }        };        ht.Default.startAnim(params);        /*window.setInterval(function() {         var rotation = plane.a('angle') + Math.PI / 10;         if (rotation > Math.PI * 2) {          rotation -= Math.PI * 2;         }         plane.a('angle', rotation);        }, 40);*/       }      }     });    }   </script>  </head>  <body onload="init();">         </body> </html> 
正文到此结束
Loading...