HT图形组件设计之道(四)

在《HT图形组件设计之道(二)》我们展示了HT在2D图形矢量的数据绑定功能,这种机制不仅可用于2D图形,HT的通用组件甚至3D引擎都具备这种数据绑定机制,此篇我们将构建一个3D飞机模型,展示如果将数据绑定机制运用于3D模型,同时会运用到HT的动画机制,以及OBJ 3D模型加载等技术细节,正巧赶上刚发布的iOS8我们终于能将基于HT for Web开发的HTML5 3D应用跑在iOS系统了。

首选我们需要一个飞机模型,采用HT for Web构建3D模型可采用API组合各种基础模型的方式,但今天我们将采用读入OBJ的方式,毕竟网上已有很多不错的现成模型素材,搜查了一番后我在www.turbosquid.com选择了的这款免费的飞机模型,这个飞机模型是3dsmax格式,飞机模型是一体化的,由于我还需要控制机头的螺旋桨,因此我用3dsmax做了点改造,将螺旋桨分离了机身独立作为一个材质,同时导出成HT for Web可读取的OBJ格式,接下来就没美工设计师什么事了,剩下就全靠我们程序员自己的代码手艺活了。

读取OBJ文件一般采用AJAX的方式远程加载,这对于喜欢纯前端的程序员来说很不爽,开发或演示个例子还得启服务,我喜欢本地文件打开就能跑不受跨域安全限制,因此我们需要将OBJ的文本信息放在在HTML或者JS代码中。解决这类问题有很多种方式,例如对于WebGL开发来说vertex shader和fragment shader代码同样面临这个问题,一种方式是写成一堆的string的array然后进行join的方式,另一种方式是增加<script id=”shader-vs” type=”x-shader/x-vertex”></script>和<script id=”shader-fs” type=”x-shader/x-fragment”></script>的自定义类似script块,然后读取相应DOM元素的textContent来获取文本内容。

但这两种方式都不适合OBJ内容,因为OBJ内容太长,采用数组方式对于成千上万行的OBJ文件行行加引号是不可思议的工作量(当然你可以再写个工具干这事),而采用<script>的方式会使得页面的HTML代码太长不易阅读编辑,我喜欢采用下面代码所示的这种方式,obj和mtl文件就像普通的js文件,可分离HTML页面代码,可给多个例子复用,且没有跨域安全问题,当然代码有点tricky,将function转换成字符串再截取中间文本内容:

var flight_mtl = getRawText(function(){/*
    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
    ...
*/});

var flight_obj = getRawText(function(){/*
    v  -21.7990 -2.5094 -157.4279
    v  -34.5972 -20.3459 -42.9317
    v  -36.7638 -6.2029 -43.0833
    ...
*/});            

function getRawText(obj){
    var text = String(obj); 
    return text.substring(14, text.length-3);
}

以下为注册飞机模型的代码,通过代码的注解可知我们对飞机模型做了调整,通过r3: [0, -Math.PI/2, 0]我将整体飞机模型沿着y轴旋转了-Math.PI弧度使之朝向右边,通过s3:[0.1, 0.1, 0.1]将飞机模型缩小了10倍。

ht.Default.loadObj(flight_obj, flight_mtl, {                    
    center: true,
    r3: [0, -Math.PI/2, 0], // make plane face right
    s3: [0.1, 0.1, 0.1], // 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';

            // add a sphere model as an indicator light
            array.push({
                shape3d: ht.Default.createSmoothSphereModel(),
                t3: [-40, 10, 0],
                s3: [6, 6, 6],
                color: {
                    func: function(data){
                        return data.a('light') ? 'red': 'black';
                    }
                }
            });
            ht.Default.setShape3dModel('plane', array);

            createPlane(rawS3);
            createFormPane();  
        } 
    }
});

飞机的螺旋桨模型绑定了data.a(‘angle’)属性,原始螺旋桨模型有点小,通过modelMap.propeller.s3 = [1, 1.2, 1.2];在yz面做了1.2倍的放大,通过modelMap.propeller.color = ‘yellow’;将原始模型的颜色改成更显眼的黄色,当然你也可以通过修改mtl文件实现,甚至再将该属性绑定数据模型进行动态变化。

飞机尾部原始模型并没有指示灯,我们通过ht.Default.createSmoothSphereModel()用API创建了一个模型,与OBJ的模型进行了组合,指示灯的颜色通过return data.a(‘light’) ? ‘red’: ‘black’;的函数逻辑进行数据绑定,后续我们将在飞机运行过程动态变化data.a(‘light’)参数,实现飞机飞行过程指示灯的闪烁效果。

飞行路线是通过ht.Polyline类型构建的,上图的几个黄色球是飞行路线Polyline对象的部分控制点,通过这几个控制点我们甚至可以在飞机飞行过程动态改变飞行路线。

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){
           var point = getPoint(v),
                px = point.x,
                py = point.y,
                pz = point.z,
                tangent = getTangent(v),
                tx = tangent.x,
                ty = tangent.y,
                tz = tangent.z;
           plane.p3(px, py, pz);
           plane.lookAt([px + tx, py + ty, pz + tz], 'right');  

           var camera = formPane.v('Camera');
           if(camera === 'Look At'){
                g3d.setCenter(px, py, pz);
           }
           else if(camera === 'First Person'){                           
                g3d.setEye(px - tx * 400, py - ty * 400 + 30, pz - tz * 400);
                g3d.setCenter(px, py, pz);                           
           }

           plane.a('angle', v*Math.PI*120);                       
           if(this.duration * t % 1000 > 500){
                plane.a('light', false);
           }else{
                plane.a('light', true);
           }                       
      },
      finishFunc: function(){
           animation = ht.Default.startAnim(params);
           plane.a('light', false);
      }                 
 };                              

 animation = ht.Default.startAnim(params);

以上为飞行动画的相关代码,ht.Default.startAnim可启动Frame-Based和Time-Based两种方式的动画,本例中我们需要动态改变飞行的周期,同时Frame-Based的方式会导致不同硬件设备总体运行周期差异太大,因此我们采用设置Duration的Time-Based的动画方式。

动画过程主要要改变飞机的位置,以及保持机头朝向切线方向,同时在Look At的模式下,我们不断让HT的Graph3dView的eye属性盯着飞机的位置,First Person模式下我们还需要改变Graph3dView的center属性。通过if(this.duration * t % 1000 > 500)的代码逻辑,实现了半秒钟改变一次light属性的闪烁效果。

为了达到更逼真的现实效果我们定义了Easing函数,采用了easeBoth这种起始结束较慢中间过程较快的动画函数,可参考《透过WebGL 3D看动画Easing函数本质》文章,从而实现飞机逐渐加速启动启动,慢慢减速着落的效果,螺旋桨的旋转角度也在动画过程中根据Easing相关参数值设置,因此螺旋桨的旋转速度也一致的放映了这种动画效果。

该例子综合运用了HT for Web的多种技术功能,大家能体会到HT这种数据绑定机制灵活且强大的特点,通过数据绑定机制,我们可以动态修改从2D拓扑图、到通用组件渲染,甚至到3D引擎的数据模型,所有图形元素的颜色、大小和角度等参数皆可灵活控制,并且以最直观易用的方式供程序员二次开发与实际业务数据绑定关联。

最后上段该HTML5例子在iOS、Android和Mac等多平台下的运行视频和抓图,有兴趣的同学还可对该例子做更多有意思的改造扩展。http://v.youku.com/v_show/id_XNzk5MzI3MzMy.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Jerry的SAP技术分享

分享一个开源的JavaScript统计图表库,40行代码实现专业统计图表

这可能是史上最简单易用的开源统计图表绘制库了。柱状图,饼状图,点状图等等您能想到的类型全部支持。

2233
来自专栏大数据文摘

五个创建交互式图表的Python库

2906
来自专栏Windows Community

UWP 手绘视频创作工具技术分享系列

开篇先来说一下写这篇文章的初衷。     初到来画,通读了来画 UWP App 的代码,发现里面确实有很多比较高深的技术点,同时也是有很多问题的,扩展性,耦合,...

35711
来自专栏知晓程序

如何优雅地发朋友圈?你需要这款简洁好看的小程序

普通的一天中,我们能看到各种各样的风景。人来人往,相遇离别,每一天,都能产生新的故事和回忆。

1714
来自专栏hightopo

HT图形组件设计之道(四)

1335
来自专栏儿童编程

《动物魔法学校》儿童学编程Scratch之“外观”部分

导读:本文通过一个案例《动物魔法学校》来学习Scratch语言的“外观”部分。之后通过一系列其他功能的综合运用对作品功能进行了扩展。

1284
来自专栏Windows Community

Microsoft Tech Summit 2018 课程简述:利用 Windows 新特性开发出更好的手绘视频应用

Microsoft Tech Summit 2018 微软技术暨生态大会将于10月24日至27日在上海世博中心举行,这也会是国内举办的最后一届 Tech Sum...

1713
来自专栏Java帮帮-微信公众号-技术文章全总结

HTML5学习-day01【悟空教程】

网页超文本应用技术工作小组是一个以推动网络HTML 5 标准为目的而成立的组织。在2004年,由Opera、Mozilla基金会和苹果这些浏览器厂商组成。

2013
来自专栏域名资讯

香飘飘奶茶上市 域名为“zjxpp”?

香飘飘终于走完了其六年的IPO之路:经证监会网站发布消息,香飘飘食品股份有限公司首发申请获通过。

540
来自专栏BestSDK

前端修仙之路:从“路人”到大神,走对这几步很重要

HTML 与 CSS基础 前端的领域里,任何东西都离不开HTML 与 CSS。HTML与CSS基本上控制了你看到的所有东西,HTML用来定义内容而CSS负责样式...

3755

扫码关注云+社区

领取腾讯云代金券