本文主要和大家分享HTML5 WebG 的3D網路拓樸結構圖,我們會從3D網路拓樸結構介紹及圖文進行詳解介紹,希望能幫助大家。
現在,3D 模型已經用於各種不同的領域。在醫療行業中使用它們製作器官的精確模型;電影業將它們用於活動的人物、物體以及現實電影;視頻遊戲產業將它們作為計算機與視頻遊戲中的資源;在科學領域將它們作為化合物的精確模型;建築業將它們用來展示提議的建築物或風景表現;工程界將它們用於設計新設備、交通工具、結構以及其它應用領域;在最近幾十年,地球科學領域開始構建三維地質模型,而且3D 模型經常做成動畫,例如,在長片電影以及電腦與電玩遊戲中大量應用三維模型。它們可以在三維建模工具中使用或單獨使用。為了容易形成動畫,通常在模型中加入一些額外的數據,例如,一些人類或動物的三維模型中有完整的骨骼系統,這樣運動時看起來會更加真實,並且可以透過關節與骨骼控制運動。
這些種種都讓我們前端開發者覺得如果我們可以不用學習 unity3d 或其他遊戲開發工具就能實現 3D 效果,而且能夠精準的靠程式碼來控制移動或方向就好了。 。 。於是我利用HT For Web 中的3D元件來實現了一個小例子,用了HT 中3D元件的大部分功能,做這個例子就是想把3D 元件好好的掌握,盡量放進一個例子中,到時候別人有需要就可以參考了。
先來看看整體實現的效果圖:
#用HT for Web,現有的3d 範本建立三層底板不是問題,問題是要如何將圖中第一層的「電腦」和「機櫃組件」放上去?我是在網上down 下來的obj 格式的文件,然後我利用HT 中的ht.Default.loadObj(objUrl, mtlUrl, params) 函數將模型加載進去,其中的params 部分可以參考http://www.hightopo. com/guide...,程式碼如下:
ht.Default.loadObj('obj/机柜组件1.obj', 'obj/机柜组件1.mtl', { //加载 obj 文件 cube: true, //是否将模型缩放到单位1的尺寸范围内,默认为false center: true, //模型是否居中,默认为false,设置为true则会移动模型位置使其内容居中 shape3d: 'box', //如果指定了shape3d名称,则HT将自动将加载解析后的所有材质模型构建成数组的方式,以该名称进行注册 finishFunc: function(modelMap, array, rawS3){ //用于加载后的回调处理 if(modelMap){ device2 = createNode('box', floor1); //创建一个节点,在第一层“地板”上 device2.p3([x1-120, y1+13, z1+60]); //设置这个节点坐标 device2.s3(rawS3); //设置这个节点大小 createEdge(device1, device2); //创建连线 device3 = createNode('box', floor1); device3.s3(rawS3); device3.p3([x1+120, y1+13, z1+60]); createEdge(device1, device3); } } });
其中finishiFunc 函數中的三個參數定義如下:
modelMap:呼叫ht.Default.parseObj 解析後的回傳值,若載入或解析失敗則傳回值為空
array:所有材質模型組成的陣列
rawS3:包含所有模型的原始尺寸
一般在實際應用中我們都會將圖元的大小設定為模型的原始尺寸。
“電腦”上方有個紅色的立體能旋轉的“警告”,是依靠ht.Default.setShape3dModel 函數(HT for Web 建模手冊http://www.hightopo.com/guide.. . 3d 模型,在ht 中,封裝好的建模函數有很多,比較基礎的就是球體,圓柱,立方體等等,這邊我用的是構造環形的方法createRingModel 來產生「警告」最外面的環,感嘆號的上部分就是用的createSmoothSphereModel 建構的球體,感嘆號的下部分就是用createSmoothCylinderModel 來建構的圓柱體。什麼用的,而且也不明白3d 模型是怎麼構成的,然後自己又重新看了前面的“模型基礎”,才知道原來3d 模型採用的一個面,最基礎的是三角面,之後復雜的面也是由多個三角面來形成的,然後繞著一個特定的軸旋轉之後形成的,當然,這個軸是你來決定的,不同的軸可以生成不同的形狀,對於顏色等風格方面的設置可以參考HT for Web 風格手冊(http://www.hightopo.com/guide...。至於如何讓這個3d 模型旋轉起來,ht 中封裝了addScheduleTask(Task) 方法,我在第三層Task 中調用了ht封裝的一個旋轉函數setRotation 來設定旋轉的順序和方向,並且指定了旋轉的物件。整體模型的顏色要用“all.blend” style 屬性):
function createAlarm(device, formPane) { var ringModel = ht.Default.createRingModel([ 8, 1, 10, 1, 10, -1, 8, -1, 8, 1 ], null, null, false, false, 100);//根据xy平面的曲线,环绕一周形成3D模型。 var sphereModel = ht.Default.createSmoothSphereModel(8, 8, 0, Math.PI*2, 0, Math.PI, 2);//构建光滑球体模型 var cylinderModel = ht.Default.createSmoothCylinderModel(8, true, true, 1, 2, 0, Math.PI*2, 8);//构建光滑圆柱体模型 var alarmArr = [//组合模型 由三个模型ringModel、sphereModel、cylinderModel组合而成 { shape3d: ringModel,//定义模型类型 r3: [Math.PI/2, 0, 0],//设置旋转角度 color: {//设置模型颜色 func: 'style@all.blend',//数据绑定style样式中的all.blend属性,可通过data.s()获取和设置这个属性 } },{ shape3d: sphereModel, t3: [0, 4, 0], color: { func: 'style@all.blend', } },{ shape3d: cylinderModel, t3: [0, -3, 0], color: { func: 'style@all.blend', } } ]; ht.Default.setShape3dModel('alarm', {//注册自定义3D模型 shape3d: alarmArr }); var alarmTip = createNode('alarm', device);//创建shape3d为alarm的节点 alarmTip.s3([2, 2, 2]);//设置节点大小 alarmTip.p3(device.p3()[0], device.p3()[1]+60, device.p3()[2]); alarmTip.s('all.blend', 'red');//改变此属性可改变模型的颜色,因为模型创建的时候已经数据绑定了 return alarmTip; }
接下來看看怎麼讓這個“告警”節點“閃爍”,我是直接將這個動畫跟節點綁定,這樣可以直接透過節點來控制動畫。閃爍的速度,以及閃爍節點的動畫等等,主要說一下這個功能在form 表單上的實現:
if(formPane){ alarmNode.scaleFunc = function() {//设置大小变化动画 var size = alarmNode.s3();//获取节点的大小 if (size[0] === 2 && size[1] === 2 && size[2] === 2) alarmNode.s3([1, 1, 1]); else alarmNode.s3([2, 2, 2]); alarmNode.scaleTimer = setTimeout(alarmNode.scaleFunc, formPane.v('scaleInterval'));//设置动画 } alarmNode.blinkFunc = function(){//设置闪烁的动画 var color = alarmNode.s('all.blend');//获取节点的style样式 if (color === 'red') alarmNode.s({'all.blend': 'yellow'});//如果节点颜色为红色,那么设置为黄色 else alarmNode.s({'all.blend': 'red'}); alarmNode.blinkTimer = setTimeout(alarmNode.blinkFunc, formPane.v('blinkInterval')); } alarmNode.rotateFunc = function() {//设置旋转动画 alarmNode.setRotation(alarmNode.getRotation() + Math.PI/20);//获取节点当前的旋转角度,在这个旋转角度之上添加 Math.PI/20 个角度 alarmNode.rotateTimer = setTimeout(alarmNode.rotateFunc, formPane.v('rotInterval')); } }
最後來說說3D 管線上的小球流動的部分,這個功能確實非常實用,而且做出來的效果也確實不錯,跟大家分享~
首先,创建一条连线连接起始节点和结束节点并设置这个连线的样式,用 ht.Edge 可以将连线吸附在起始节点和结束节点上,这样移动这两个节点中的任意一个节点连线都会跟着节点移动的位置变化,非常方便:
var polyline = new ht.Edge(source, target);//创建连线 dataModel.add(polyline);//将连线添加进数据容器中 polyline.s({ 'edge.width': 5,//连线宽度 'edge.type': 'points',//连线类型 为points时连线走向将由edge.points属性决定,用于绘制折线 'edge.points': [//可设置类型为ht.List的{x:100, y:100}格式的点对象数组,当edge.type为points时起作用 {x: source.getPosition3d()[0]+200, y: source.getPosition3d()[2], e: source.getPosition3d()[1]}, {x: target.getPosition3d()[0]+400, y: target.getPosition3d()[2], e: target.getPosition3d()[1]} ], 'edge.segments': [1, 4],//用于描述点连接样式,数组元素为整型值 'shape3d': 'cylinder',//圆柱 'shape3d.color': 'rgba(242, 200, 40, 0.4)', 'shape3d.resolution': 30,//微分段数,可以决定曲线的平滑度 'edge.source.t3': [20, 0, 0],//连线source端偏移,[tx, ty, tz]格式,默认为空 'edge.target.t3': [20, 0, 0]//连线target端偏移,[tx, ty, tz]格式,默认为空 });
因为我们在创建连线的时候设置的 points 仅为曲线上的两个点,所以如果要获取曲线目前形成的点,是缺少 source 和 target 两个点的,我们重新设置一个数组,将这两个点添加进去,后面获取曲线上所有点时会用上:
var list = new ht.List(); list.push({x: source.getPosition3d()[0], y: source.getPosition3d()[2], e: source.getPosition3d()[1]});//向数组中添加source点 polyline.s('edge.points').each(function(item){//添加style属性中已设置的两个点 list.push(item); }); list.push({x: target.getPosition3d()[0], y: target.getPosition3d()[2], e: target.getPosition3d()[1]});//添加target点
然后创建一个在管线上滑动的小球节点,这是仅是设置节点,真正添加进数据容器 dataModel 中需要设置完小球的坐标时再添加,如果没有给节点设置位置就将节点添加进数据容器中,节点的初始位置就是 3D 场景的正中心 [0, 0, 0] 的位置。小球滑动的动画代码如下:
var ball = new ht.Node();//创建小球节点 ball.s({//设置小球节点的样式 'shape3d': 'sphere',//设置小球的3d模型为球形 'shape3d.color': 'rgba(40, 90, 240, 0.4)'//设置3d模型的颜色 }); var delta = 10, flag = 0; setInterval(function(){ flag++; var length = (polyline.a('total') || 0) % polyline.a('length') + delta;//小球当前走过的曲线长度 var cache = ht.Default.getLineCacheInfo(list, polyline.s('edge.segments'));//获取曲线上的点的信息 var lineLength = ht.Default.getLineLength(cache);//获取曲线的总长度 polyline.a('length', lineLength - 50);//因为我设置了edge的t3(相当于2d中的offset),所以线段长度实际没有那么长 var offset = ht.Default.getLineOffset(cache, length);//曲线根据曲线上点的信息的偏移量 ball.setPosition3d(offset.point.x + 10, offset.point.y, offset.point.z);//设置节点的坐标 polyline.a('total', length); if(flag === 1) dataModel.add(ball);//这时候节点已经有了坐标了,可以添加进数据容器中了 }, 10);
我们还可以看到第二层上有两个特殊的多边形“平行四边形”和“梯形”,平行四边形是靠 createParallelogramModel 模型函数,这个函数比较简单,createExtrusionModel(array, segments, top, bottom, resolution, repeatUVLength, tall, elevation),array 是你要形成的图形的坐标点,这边只是针对于 xz 轴上画的平面图形,segments 指的是如何连接这几个坐标点,可参考 HT for Web 形状手册(http://hightopo.com/guide/gui...),top 和 bottom 就是让你选择是否有顶部或者底部,resolution 微分段数,我们描绘一段曲线的时候可能只要确认几个个别的点然后在每两个点之间的连线上把它分成多个段,这样这条线段就会变得平滑,ht 为了用户能够轻松操作这些线段,就封装了这一个参数,repeatUVLength 默认为空,设置值后顶部和底部的贴图将根据制定长度值进行重复,tall 模型的高度,默认为 5,elevation 模型中心的 y 轴位置,默认值为 0,设置这个值可以使 xz 上的平面绕着 y 轴旋转。
底层的一个环形的效果是通过一个算法来实现的,环形得确认这个环形上有多少个元素,然后算每两个之间的角度,在通过 sin、cos 来计算每一个元素的位置,得出了如下代码:
names = ['设备2', '设备3', '设备4', '设备5', '设备6', '设备7', '设备8', '设备9']; names.forEach(function(name, index) { x = 400, y = 200, angle = 45, r = 120; x = x3 + Math.sin((2 * Math.PI / 360) * angle * index) * r; y = z3 + Math.cos((2 * Math.PI / 360) * angle * index) * r; device = createRect([x, y3 + 15, y], [w * 0.1, 15, h * 0.1], '', '', floor3); createEdge(device5, device); });
相关推荐:
以上是HTML5 WebG 的3D網路拓樸結構圖的詳細內容。更多資訊請關注PHP中文網其他相關文章!