在WebGL场景中使用2DA,使用Chrome控制台实行3D模型编辑的品尝

前言:3D模型编辑的主题是对极端地点和纹理颜色的编纂,这几个研商的意在寻找一种通过编制程序格局间接对模型举行编写制定的艺术,那种编辑方法和如今流行的通过鼠标点选、拖拽举办编辑的格局之间的涉嫌,和前端编制程序中“程序员编写静态网页”与“美术工作实行网页切图”之间的关联很相像。

    
那篇小说将钻探什么在三个自定义的当地网格上进展简短的2D寻路,以及鲜明路径后什么运用基于物理引擎的活动格局使实体沿路径到达指标地址。读者需求事先对WebGL和Babylonjs知识有一些打听,能够参照我录像的WebGL入门录像教程和翻译的官方入门文书档案,当然也足以用本人喜欢的别样措施来学学。

在WebGL场景中使用2DA*寻路,webgl2da

    
那篇文章将讨论什么在八个自定义的本地网格上进展简短的2D寻路,以及显著路径后怎么行使基于物理引擎的位移格局使实体沿路径到达目的地址。读者供给事先对WebGL和Babylonjs知识有部分摸底,能够参考笔者录制的WebGL入门录像教程和翻译的合法入门文档,当然也可以用自身喜爱的别的艺术来学学。

  小说重要分为如下几有的:

  ① 、自定义地面网格与寻路矩阵

  2、生成Babylon格式3D模型

  3、使用pathfinding库进行2D寻路

  四 、基于cannon.js物理引擎使实体沿路径移动

  场景能够经过

  场景如下图:

澳门葡京 1

  使用WASD控制自由相飞机地点置,移动鼠标控制视角,右键点击地面会在本地上停放一个“指标方块”,然后标有“农民”标志的小球会向指标方块移动。

  场景中使用了2DA*寻路算法,如下图所示:

澳门葡京 2

  当对象方块位于障碍的另1只时,农民会尽大概寻找最短的门径绕开障碍物前往目的方块。

① 、自定义地面网格与寻路矩阵:

a、在Babylon.js渲染引擎中自定义地面网格

 1     var vdata_ground=new BABYLON.VertexData.CreateGround({width:198,height:198,subdivisionsX:99,subdivisionsY:99});//分成了99段,一条边上100个顶点
 2     var arr_vposition=vdata_ground.positions;
 3     var map=[];
 4     var len=arr_vposition.length/3;//和挨个遍历比起来,似乎有目的的去找更好
 5     for(var i=20;i<81;i++)//对于这个范围内的行
 6     {
 7         for(var j=20;j<23;j++)//对于这个范围内的列
 8         {
 9             arr_vposition[(j+100*i)*3+1]=1;
10         }
11     }
12     for(var i=20;i<81;i++)//对于这个范围内的行
13     {
14         for(var j=40;j<43;j++)//对于这个范围内的列
15         {
16             arr_vposition[(j+100*i)*3+1]=2;
17         }
18     }
19     for(var i=20;i<81;i++)//对于这个范围内的行
20     {
21         for(var j=60;j<63;j++)//对于这个范围内的列
22         {
23             arr_vposition[(j+100*i)*3+1]=4;
24         }
25     }
26     BABYLON.VertexData._ComputeSides(0, arr_vposition, vdata_ground.indices, vdata_ground.normals
27         , vdata_ground.uvs);
28     var mesh_ground=new BABYLON.Mesh("mesh_ground",scene);
29     mesh_ground.renderingGroupId=2;
30     vdata_ground.applyToMesh(mesh_ground, true);

   第壹行创造了1个Ground类型的Babylonjs“顶点数据”对象,这几个指标涵盖了建立地点网格所需的顶点地点、法线、纹理坐标、顶点索引数据(提出读者亲自用调节和测试情势看一下那几个指标的组织),构造函数中的四个198象征当地的长宽是198,三个99代表每一条边被分成99段(由玖十八个极点组成,每多少个极点之间的离开为2),至于为啥设置为99段后文仲有表达,那时的本土网格假使渲染出来将是二个平面。

  要让地方变得坑坑洼洼有两种思路:在中度变化的点的比重较大时,能够品尝对种种终端进行遍历,然后依据某种规则变更顶点的万丈;在比例较小时提议直接在缓存数组中找到那几个极端进行更改,显著后者速度更快。

  第②6行根据顶点数据对各种面包车型地铁正面与反面举行测算,在对网格的顶峰消息进行修改后一般都要履行这一条语句,而另一条平日在它前边实施的讲话是:“

BABYLON.VertexData.ComputeNormals(positions, indices, normals);

”,它的效能是在顶峰数据变化后再度计算法线方向。那里不履行那条语句的因由是Babylonjs中的地面网格是一种“简化”的网格

  如图所示:

澳门葡京 3

  同样表示三个方块,简化的主意选取四个终端,顶点之间的片元数据由顶点数据插值而成,因为左侧的方框和左边的正方共用了三个极点,所以那多个方块的法线方向和纹理坐标必定是连接的。而用非简化的不二法门意味着那三个方块,则供给使用八个顶峰,缺点是增添了对质量的消耗,优点是法线方向和纹理坐标不必总是,能够展开完全区别的变型。

  因为使用了简化的措施,地面网格的同2个极端处于多少个不一样的平面中,使用ComputeNormals总结地面网格的极限的法线方向也就错过了意思,事实上Babylonjs把地面网格顶点的法线方向都暗中同意为竖直向上。

  后边的代码建立了叁个空的网格,将网格的渲染组织设立为2,将顶点数据交由这么些空网格对象。

  生成的网格如下图所示:

澳门葡京 4

 

b、建立2D寻路矩阵

  在寻路场景中利用的pathfinding库需求用三个矩阵(二维数组)来定义障碍物的义务,在这之中零元素表示这么些地块能够通达,不为零的要素表示无能为力通行,上面是白手起家那个数组的章程:

 1     mesh_ground.mydata={};
 2     mesh_ground.mydata.walkabilityMatrix=MakewalkabilityMatrix(arr_vposition,99,99,2);
 3     mesh_ground.mydata.len_x=99;
 4     mesh_ground.mydata.len_y=99;
 5     mesh_ground.mydata.len_s=2;
 6     
 7     。
 8     。
 9     。
10     
11 //对每个正方形区块的倾斜程度进行计算,得出是否可以通行
12 //顶点数据,寻路空间宽度,寻路空间高度,每个方格区域的边长
13 function MakewalkabilityMatrix(arr,len_x,len_y,len_s)
14 {
15     var arr_Matrix=numeric.rep([len_y,len_x],0);
16     var len_s2=len_s*0.707;//求得平均点到其中一个边线点的水平距离0.7071067811865476
17     //var len_s2a=len_s2;
18     //var len_s2b=len_s2;
19     //var len_s2c=len_s2;
20     for(var i=0;i<len_y;i++)//对于每一行寻路单元格
21     {
22         for(var j=0;j<len_x;j++)//对于这一行里的每一个单元格
23         {
24             var int1=j+i*(len_x+1);
25             var int2=j+i*(len_x+1)+1;
26             var int3=j+(i+1)*(len_x+1);
27             var int4=j+(i+1)*(len_x+1)+1;
28             var y1=arr[int1*3+1];
29             var y2=arr[int2*3+1];
30             var y3=arr[int3*3+1];
31             var y4=arr[int4*3+1];
32             var ya=(y1+y2+y3+y4)/4;
33             var yb=Math.max(Math.abs(y1-ya),Math.abs(y2-ya),Math.abs(y3-ya),Math.abs(y4-ya));
34             arr_Matrix[i][j]=parseInt((yb)/0.707);//高度超过了水平距离几倍就认为是几倍的障碍物
35         }
36     }
37     return arr_Matrix;
38 }

  这一段代码的思绪是:将当地网格垂直方向的正投影作为寻路单元格,取每一个寻路单元格的八个终端,算出那四个终端的平分高度与种种终端高度的差的最大值与寻路单元格主题点到极限的档次距离的比,将这些比率作为“障碍程度”(一句话来说正是极限高度变化的竹马戏烈,障碍就越难跨越)。然后为网格添加三个mydata属性(JavaScript语言的优势),把和寻路矩阵有关的音讯放到那么些天性里。

  那里运用了numeric数学库,可以在

  2、生成babylon格式的3D模型:

  网格生成终结后供给拿到别的程序中动用,那里本身选用把它保存为babylon格式的3D模型,babylon是一种json字符串模型文件,其亮点是结构不难意义周详。

  Babylon.js的官方网站上有完整的格式表达和例子:

  以下是浮动对应json的代码:

  1 /**
  2  * Created by Administrator on 2017/7/14.
  3  */
  4 function Export_mesh(arr_mesh,PngName)//用Babylon格式导出模型
  5 {
  6     //场景对象
  7     var obj_scene=
  8     {
  9         'autoClear': true,
 10         'clearColor': [0,0,0],
 11         'ambientColor': [0,0,0],
 12         'gravity': [0,-9.81,0],
 13         'cameras': [{
 14             'name': 'Camera',
 15             'id': 'Camera',
 16             'position': [7.4811,5.3437,-6.5076],
 17             'target': [-0.3174,0.8953,0.3125],
 18             'fov': 0.8576,
 19             'minZ': 0.1,
 20             'maxZ': 100,
 21             'speed': 1,
 22             'inertia': 0.9,
 23             'checkCollisions': false,
 24             'applyGravity': false,
 25             'ellipsoid': [0.2,0.9,0.2]
 26         }],
 27         'activeCamera': 'Camera',
 28         'lights': [{
 29             'name': 'Sun',
 30             'id': 'Sun',
 31             'type': 1,
 32             'position': [0.926,7.3608,14.1829],
 33             'direction': [-0.347,-0.4916,-0.7987],
 34             'intensity': 1,
 35             'diffuse': [1,1,1],
 36             'specular': [1,1,1]
 37         }],
 38         'materials':[{
 39             'name': 'mball',
 40             'id': 'mball',
 41             'ambient': [1,1,1],
 42             'diffuse': [1,1,1],
 43             'specular': [1,1,1],
 44             'specularPower': 50,
 45             'emissive': [0,0,0],
 46             'alpha': 1,
 47             'backFaceCulling': true,
 48             'diffuseTexture': {
 49                 'name': PngName?PngName:'snow2.jpg',
 50                 'level': 1,
 51                 'hasAlpha': 1,
 52                 'coordinatesMode': 0,
 53                 'uOffset': 0,
 54                 'vOffset': 0,
 55                 'uScale': 1,
 56                 'vScale': 1,
 57                 'uAng': 0,
 58                 'vAng': 0,
 59                 'wAng': 0,
 60                 'wrapU': true,
 61                 'wrapV': true,
 62                 'coordinatesIndex': 0
 63             }
 64         }],
 65         'geometries': {},
 66         'meshes': [],
 67         'multiMaterials': [],
 68         'shadowGenerators': [],
 69         'skeletons': [],
 70         'sounds': [],
 71         'mydata':{'walkabilityMatrix':[]}
 72     };
 73     //所有模型组件的父物体
 74     var obj_allbase=
 75     {
 76         'name': 'allbase',
 77         'id': 'allbase',
 78         'materialId': 'mball',
 79         'position': [0,0,0],
 80         'rotation': [0,0,0],
 81         'scaling': [1,1,1],
 82         'isVisible': true,
 83         'isEnabled': true,
 84         'checkCollisions': false,
 85         'billboardMode': 0,
 86         'receiveShadows': true,
 87         'positions': [],
 88         'normals': [],
 89         'uvs': [],
 90         'indices': [],
 91         'subMeshes': [{
 92             'materialIndex': 0,
 93             'verticesStart': 0,
 94             'verticesCount': 0,
 95             'indexStart': 0,
 96             'indexCount': 0
 97         }]
 98     };
 99     obj_scene.meshes.push(obj_allbase);
100     var len=arr_mesh.length;
101     var all_x=0;
102     var all_y=0;
103     var all_z=0;
104     for(var i=0;i<len;i++)
105     {
106         var obj_child={};
107         if(arr_mesh[i].geometry._vertexBuffers!=null)
108         {
109             var child=arr_mesh[i];
110             if(!child.mydata)
111             {
112                 child.mydata={}
113             }
114             var vb=child.geometry._vertexBuffers;
115             all_x+=child.position.x;
116             all_y+=child.position.y;
117             all_z+=child.position.z;
118             obj_child=
119             {
120                 'name': child.name,
121                 'id': child.id,
122                 'parentID': 'allbase',
123                 'materialId': 'mball',
124                 'position': [child.position.x,child.position.y,child.position.z],
125                 'rotation': [child.rotation.x,child.rotation.y,child.rotation.z],
126                 'scaling': [child.scaling.x,child.scaling.y,child.scaling.z],
127                 'isVisible': true,
128                 'isEnabled': true,
129                 'checkCollisions': false,
130                 'billboardMode': 0,
131                 'receiveShadows': true,
132                 'positions': vb.position._buffer._data,
133                 'normals': vb.normal._buffer._data,
134                 'uvs': vb.uv._buffer._data,
135                 'indices': child.geometry._indices,
136                 'subMeshes': [{
137                     'materialIndex': 0,
138                     'verticesStart': 0,
139                     'verticesCount': vb.position._buffer._data.length,
140                     'indexStart': 0,
141                     'indexCount': child.geometry._indices.length
142                 }],
143                 'mydata':child.mydata
144             };
145             obj_scene.meshes.push(obj_child);
146         }
147     }
148     //不能让模型的主体过于偏离模型的中心
149     all_x=all_x/len;
150     all_y=all_y/len;
151     all_z=all_z/len;
152     for(var i=1;i<len+1;i++)
153     {
154         obj_scene.meshes[i].position[0]-=all_x;
155         obj_scene.meshes[i].position[1]-=all_y;
156         obj_scene.meshes[i].position[2]-=all_z;
157     }
158     var str_data=JSON.stringify(obj_scene);
159     DownloadText(MakeDateStr()+"testscene",str_data,".babylon");
160 }

  能够看出,二个babylon文件能够涵盖多少个网格对象,除了网格对象之外那个模型文件还是能够储存场景、光照、相机、动画、骨骼等音讯,那么些职能能够接纳性使用。方法的结尾采纳DownloadText方法将json文本导出,DownloadText是自己参考网络资料编辑的字符下载方法,假使不选用DownloadText,直接在Chrome浏览器的调节和测试格局下的指令行里输入“console.log(str_data)”也能获得json字符串。

  DownloadText内容如下:

澳门葡京 5

  1 /**
  2  * Created by Administrator on 2015/3/2.
  3  */
  4 /**
  5  * 将指定字符写入指定名称的文本文件中,并可以选择本地保存目录,兼容IE11和谷歌浏览器
  6  */
  7 function DownloadText(filename,content,filetype)
  8 {
  9     if(filetype==null)
 10     {
 11         filetype=".txt";
 12     }
 13     if(document.createElement("a").download!=null)//谷歌和火狐
 14     {
 15         var aLink = document.createElement('a');
 16         var datatype="data:text/plain;charset=UTF-8,";
 17         if(filetype==".xml")
 18         {
 19             datatype="data:text/xml;charset=UTF-8,";
 20         }
 21         if(filetype==".babylon")
 22         {//浏览器还没有支持babylon的mime类型!!
 23             datatype="data:text/plain;charset=UTF-8,";
 24         }
 25         if(filetype==".png"||filetype==".jpeg")
 26         {
 27             datatype="";
 28         }
 29         if(content.length<1000000)
 30         {
 31             aLink.href = datatype+content;//dataurl格式的字符串"
 32         }
 33         else
 34         {//对于过大的文件普通dataURL不支持,所以使用“二进制流大对象”
 35             aLink.href=URL.createObjectURL(new Blob([content],{type:"text/plain"}));
 36         }
 37         aLink.download = filename;
 38         aLink.innerHTML=filename;
 39         //aLink.setAttribute("onclick","");
 40         aLink.onclick=function()
 41         {
 42             document.getElementById("div_choose").style.display="none";
 43             //delete_div('div_choose');
 44             delete_div('div_mask');
 45         }
 46         //aLink.style.display="none";
 47         //document.body.appendChild(aLink);
 48         /*var evt = document.createEvent("HTMLEvents");//建立一个事件
 49         evt.initEvent("click", false, false);//这是一个单击事件
 50         evt.eventType = 'message';
 51         aLink.dispatchEvent(evt);//触发事件*/
 52         //chrome认为点击超链接下载文件是超链接标签的“默认属性”,谷歌认为默认属性不可以用脚本来触发,所以从M53版本开始dispatchEvent无法触发超链接下载
 53         //window.open(datatype+content, "_blank");
 54         //document.write(datatype+content);
 55         delete_div('div_choose');
 56         delete_div('div_mask');
 57         var evt=evt||window.event;
 58         cancelPropagation(evt);
 59         var obj=evt.currentTarget?evt.currentTarget:evt.srcElement;
 60 
 61         Open_div("", "div_choose", 240, 180, 400, 80, "", "",1,401);//打开一个带遮罩的弹出框
 62         var div_choose=$("#div_choose")[0];
 63         div_choose.style.border="1px solid";
 64         div_choose.innerHTML="谷歌浏览器专用文件生成完毕,请点击下面的文件名下载文件。<br>"
 65         div_choose.appendChild(aLink);
 66         drag(div_choose);//让弹出框可以被拖拽
 67         aLink.onmousedown=function()
 68         {
 69             var evt=evt||window.event;
 70             cancelPropagation(evt);
 71         }
 72     }
 73     else//IE
 74     {
 75         var Folder=BrowseFolder();
 76         if(Folder=="false")
 77         {
 78             alert("保存失败!");
 79         }
 80         else
 81         {
 82             var fso, tf;
 83             fso = new ActiveXObject("Scripting.FileSystemObject");//创建文件系统对象
 84             tf = fso.CreateTextFile(Folder + filename+filetype, true,true);//创建一个文件
 85             tf.write(content);
 86             tf.Close();
 87             alert("保存完毕!");
 88         }
 89     }
 90 }
 91 function BrowseFolder()
 92 {//使用ActiveX控件
 93     try
 94     {
 95         var Message = "请选择保存文件夹";  //选择框提示信息
 96         var Shell = new ActiveXObject( "Shell.Application" );
 97         var Folder = Shell.BrowseForFolder(0,Message,0x0040,0x11);//起始目录为:我的电脑
 98         //var Folder = Shell.BrowseForFolder(0,Message,0); //起始目录为:桌面//选择桌面会报错!!
 99 
100         if(Folder != null)
101         {
102             Folder = Folder.items();  // 返回 FolderItems 对象
103             Folder = Folder.item();  // 返回 Folderitem 对象
104             Folder = Folder.Path;   // 返回路径
105             if(Folder.charAt(Folder.length-1) != "\\")
106             {
107                  Folder = Folder + "\\";
108             }
109             //document.all.savePath.value=Folder;
110             return Folder;
111         }
112     }
113     catch(e)
114     {
115         return "false";
116         alert(e.message);
117     }
118 }

View Code

  接下去,大家要在另三个先后中动用方面生成的模子文件,使用Babylonjs的能源管理器加载网格:

 1     this.loader =  new BABYLON.AssetsManager(this.scene);//资源管理器
 2 
 3     // 资源数组
 4     this.assets = {};
 5     //为资源管理器分配一个任务
 6     var meshTask = this.loader.addMeshTask("gun", "", "./assets/", "gun.babylon");
 7     meshTask.onSuccess = function(task) {//这个任务完成
 8         _this._initMesh(task);
 9     };    
//第一个参数表示task的name,第二个参数表示加载模型文件中的哪个网格,为空则用数组形式加载全部,第三个参数表示路径,第四个参数是文件名
10     var meshTask2 = this.loader.addMeshTask("mesh_ground", "", "./assets/arena/", "2017810_14_12_59testscene.babylon");
11     meshTask2.onSuccess = function(task) {
12         _this._initMesh(task);
13     };
14 
15     this.loader.onFinish = function (tasks)//所有任务完成
16     {
17     。。。
18     }
19     
20     。
21     。
22     。
23     
24     _initMesh : function(task)
25     {
26         this.assets[task.name] = task.loadedMeshes;
27         for (var i=0; i<task.loadedMeshes.length; i++ ){
28             var mesh = task.loadedMeshes[i];
29             mesh.isVisible = false;
30             //预先把所有资源加载下来,但不显示,当需要时再把它显示在需要的位置,或者在需要的位置,建立一个资源的实例(克隆)
31         }
32     }
33     

澳门葡京,  这时,会生出2个小意思:Babylonjs并不帮忙大家夹带在mesh中的mydata属性。化解办法是在babylon.30.all.max.js的21272行附近修改:

1             if (parsedMesh.metadata !== undefined) {
2                 mesh.metadata = parsedMesh.metadata;
3             }
4             if (parsedMesh.mydata !== undefined) {
5                 mesh.mydata = parsedMesh.mydata;
6             }    

  仿照metadata的写法加上对mydata的援助,当然,也足以考虑把mydata夹带到任何被mesh所援救的习性里。

   3、使用pathfinding库进行2D寻路

  pathfindingjs是一个开源2D寻路库,能够在

  pathfinding的为主用法如下:

 1 var finder = new PF.AStarFinder({//“寻路器”
 2     diagonalMovement: 3
 3 });
 4 
 5 。
 6 this.grid=new PF.Grid(this.len_x,this.len_y,this.walkabilityMatrix);//生成寻路网格 7 。


 8 
 9 function FindWaytogo(pickResult)//pickResult是Babylonjs中定义的“鼠标选取结果”对象
10 {
11     var faceId=pickResult.faceId;//点击了网格中的第几个面
12     var pickedMesh=pickResult.pickedMesh;//被点击的网格
13     var px=MyGame.player.mesh.position.x;//被控对象在场景中的水平位置
14     var py=MyGame.player.mesh.position.z;
15 
16     var len_x=MyGame.arena.len_x;//寻路网格的格数和每格的长度
17     var len_y=MyGame.arena.len_y;
18     var len_s=MyGame.arena.len_s;
19     if(px>-len_x*len_s/2&&px<len_x*len_s/2&&py>-len_y*len_s/2&&py<len_y*len_s/2&&MyGame.arena.grid)//如果使用了pathfinder的障碍矩阵
20     {
21         var arr_matrix=MyGame.arena.walkabilityMatrix;//寻路矩阵
22         var count=parseInt(faceId/2);//第几个方格
23         //接下来要把网格的面转换为寻路方格的坐标,后面还要把寻路方格的坐标转换为scene中的位置
24         //面数转换为方格坐标
25         var count_y=parseInt(count/len_x);
26         var count_x=count%len_x;
27         //场景坐标转化为方格坐标
28         var count_x0=parseInt(px/len_s+len_x/2);
29         var count_y0=parseInt(-py/len_s+len_y/2);
30 
31         //寻路,返回一个由方格坐标组成的数组
32         var path = finder.findPath(count_x0,count_y0 , count_x,count_y, MyGame.arena.grid.clone());//这些是寻路网格坐标
33         var len=path.length;
34         for(var i=0;i<len;i++)
35         {//把方格坐标转化为场景坐标
36             var obj=path[i];
37             obj[0]=(obj[0]-len_x/2)*len_s;
38             obj[1]=(-obj[1]+len_y/2)*len_s;
39         }
40 
41         path.push([pickResult.pickedPoint.x,pickResult.pickedPoint.z]);
42         MyGame.player.path_goto=path;//在使用时在生成高度
43         MyGame.player.positiontogo=[pickResult.pickedPoint.x,pickResult.pickedPoint.z];
44         path.shift();//把第一个出发节点去掉
45         console.log("生成路径,起点:["+px+","+py+"],终点:["+pickResult.pickedPoint.x+","+pickResult.pickedPoint.z+"]");
46     }
47 }

  那样,大家就把场景中的地点对应成了寻路网格中的地方,然后选择pathfinding生成了2D门路。必要专注的是pathfinding中的grid对象只好动用二遍,再度寻路时必要重新生成grid也许采用grid的克隆对象。

 

  ④ 、基于cannon.js物理引擎沿路径移动 

  接下去必要让被控物体沿着钦命的门径运动,为了能让实体在坎坷不平的地形中活动时保持紧贴地面,作者在那边运用了cannonjs物理引擎(关于物理引擎的用法能够参考上一篇小说)。经过考试,那个版本的cannonjs的单个物理仿真器最多扶助对一千0个终端的物理仿真,所从前文无法把本地网格分成愈多段。

  大家在那么些场景中监听“右键点击地面”的风云,代码如下:

 1 canvas.addEventListener("click", function(evt) {
 2             var width = engine.getRenderWidth();
 3             var height = engine.getRenderHeight();
 4             var pickInfo = scene.pick(width/2, height/2, null, false, _this.camera);//点击信息
 5             if(evt.button==2)//右键单击
 6             {
 7                 cancelEvent(evt);//阻止默认响应
 8                 if(pickInfo.hit&&pickInfo.pickedMesh.name=="mesh_ground")//点击到了地面上
 9                 {
10                     MyGame.player.mesh.physicsImpostor.setMass(70);//给被控物体赋予质量,这样它才可以下落
11                     FindWaytogo(pickInfo);//在玩家到点击目的地之间找到一条路径
12                     var mesh_togo=BABYLON.Mesh.CreateBox("box", 1, scene);//目标方块
13                     mesh_togo.position = pickInfo.pickedPoint.clone();//pickResult.pickedPoint
14                     mesh_togo.renderingGroupId=2;
15                     MyGame.player.mesh_togo=mesh_togo;
16                 }
17             }
18 
19 
20 
21         }, false);

  然后在每趟渲染在此之前实施以下运动情势:

 1         scene.registerBeforeRender(function() {
 2             if(MyGame.flag_startr==1)//如果开始渲染了
 3             {
 4                 if(MyGame.flag_view=="first"||MyGame.flag_view=="third")
 5                 {
 6                     physics20170725(MyGame.player);
 7                 }
 8                 if(MyGame.flag_view=="free")
 9                 {
10                     pathgoto20170808(MyGame.player);
11                 }
12             }
13         });

 

 1 function pathgoto20170808(obj)//obj是player
 2 {
 3     if(true)
 4     //if(obj.standonTheGround==1)//站在地面上时考虑将质量设为0?
 5     {
 6         if(obj.path_goto!="sleep"&&obj.path_goto!="lose")
 7         {
 8             var len_x=MyGame.arena.len_x;
 9             var len_y=MyGame.arena.len_y;
10             var len_s=MyGame.arena.len_s;
11             var vl_now=obj.mesh.physicsImpostor.getLinearVelocity();
12 
13             if(obj.path_goto.length>0)
14             {
15                 var px=obj.mesh.position.x;//全是场景坐标!!
16                 var py=obj.mesh.position.z;
17                 var count_x0=px;
18                 var count_y0=py;
19                 var count_x=obj.path_goto[0][0];
20                 var count_y=obj.path_goto[0][1];
21                 var len=obj.path_goto.length;
22                 var count_x2=obj.path_goto[len-1][0];
23                 var count_y2=obj.path_goto[len-1][1];
24                 var y_obj=obj.mesh.position.y;
25                 if((Math.pow(count_x0-count_x2,2)+Math.pow(count_y0-count_y2,2))<0.25*len_s*len_s)
26                 {//在移动过程中因未知原因跳到距终点0.5以内距离的地方,直接寻找最终点
27                     console.log("在最终格内");
28                     if((Math.pow(count_x0-count_x2,2)+Math.pow(count_y0-count_y2,2))<0.01*len_s*len_s)//到达0.1距离以内的地方,认为到达最终目标,直接定位
29                     {
30 
31                         obj.mesh.position.x=count_x;
32                         obj.mesh.position.z=count_y;
33                         obj.path_goto="sleep";
34                         console.log("到达最终目标:["+obj.mesh.position.x+","+obj.mesh.position.y+","+obj.mesh.position.z+"]");
35                         obj.mesh.physicsImpostor.setMass(0);//质量设为零将不会下落
36                         obj.mesh_togo.dispose();
37                         obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
38                         obj.mesh.physicsImpostor.setLinearVelocity(new BABYLON.Vector3(0,0,0));
39                         
40                     }
41                     else{
42                         var v_temp=new BABYLON.Vector3(count_x2,0,count_y2).subtract(new BABYLON.Vector3(obj.mesh.position.x,0,obj.mesh.position.z)).normalize().scaleInPlace(obj.vm.forward);
43                         v_temp.y=vl_now.y<=0?vl_now.y:0;//这个单位应该脚踏实地的平稳运动
44                         obj.mesh.physicsImpostor.setLinearVelocity(v_temp);
45                         //obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
46                         if(obj.path_goto.length>1)
47                         {
48                             obj.path_goto=[obj.path_goto[len-1]];//只剩一个最终目标
49                         }
50                     }
51                 }
52                 else if((Math.pow(count_x0-count_x,2)+Math.pow(count_y0-count_y,2))>4*len_s*len_s)
53                 {//在移动过程中因未知原因跳到距下个目标格2以外距离的地方,需要重新寻路,这种计算可能耗时较大,不能每帧执行!!
54                     obj.path_goto="lose";
55                     //obj.mesh.physicsImpostor.setMass(0);//不掉落
56                     obj.mesh.physicsImpostor.setLinearVelocity(new BABYLON.Vector3(0,0,0));
57                     obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
58                     return false;
59                 }
60                 else if(obj.path_goto.length>1&&(Math.pow(count_x0-count_x,2)+Math.pow(count_y0-count_y,2))<0.25*len_s*len_s)
61                 {//距离下一寻路格足够近,切换下一寻路格
62 
63                     obj.path_goto.shift();
64                     count_x=obj.path_goto[0][0];
65                     count_y=obj.path_goto[0][1];
66                     console.log("切换下一个寻路单元格:["+count_x+","+count_y+"]");
67                     var v_temp=new BABYLON.Vector3(count_x,0,count_y).subtract(new BABYLON.Vector3(obj.mesh.position.x,0,obj.mesh.position.z)).normalize().scaleInPlace(obj.vm.forward);
68                     v_temp.y=vl_now.y<=0?vl_now.y:0;
69                     obj.mesh.physicsImpostor.setLinearVelocity(v_temp);
70                     //obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
71                 }
72                 else//正常向目标寻路格移动
73                 {
74                     console.log("普通寻路");
75                     var v_temp=new BABYLON.Vector3(count_x,0,count_y).subtract(new BABYLON.Vector3(obj.mesh.position.x,0,obj.mesh.position.z)).normalize().scaleInPlace(obj.vm.forward);
76                     v_temp.y=vl_now.y<=0?vl_now.y:0;
77                     obj.mesh.physicsImpostor.setLinearVelocity(v_temp);
78                     //obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
79                 }
80 
81             }
82         }
83         else
84         {
85             //obj.mesh.physicsImpostor.setMass(0);//不掉落
86         }
87     }
88 
89 
90 
91 }

  那里分二种或然发生的移位情形(最普遍的三种)分别设置被控物体的线速度,使得物体平稳的沿着路径运动,当物体到达指标时将跻身sleep状态,当物体偏离路径时将跻身lose状态,程序每分钟检查一下物体是或不是lose,假诺lose则另行寻路(没有测试过):

 1 _this.currentframet=new Date().getTime();
 2                 _this.DeltaTime=_this.currentframet-_this.lastframet;//取得两帧之间的时间
 3                 _this.lastframet=_this.currentframet;
 4                 _this.nohurry+=_this.DeltaTime;
 5                 if(MyGame&&_this.nohurry>1000)//每一秒进行一次导航修正
 6                 {
 7                     _this.nohurry=0;
 8                     if(_this.player.path_goto=="lose")//发现迷失了路途
 9                     {
10                         console.log("发现迷路,重新规划路径");
11                         var len_x=MyGame.arena.len_x;
12                         var len_y=MyGame.arena.len_y;
13                         var len_s=MyGame.arena.len_s;
14                         //场景坐标转化为方格坐标
15                         var count_x0=parseInt(_this.player.mesh.position.x/len_s+len_x/2);
16                         var count_y0=parseInt(-_this.player.mesh.position.z/len_s+len_y/2);
17                         var count_x=parseInt(_this.player.positiontogo[0]/len_s+len_x/2);
18                         var count_y=parseInt(-_this.player.positiontogo[1]/len_s+len_y/2);
19                         var path = finder.findPath(count_x0,count_y0 , count_x,count_y, MyGame.arena.grid.clone());//这些是寻路网格坐标
20                         var len=path.length;
21                         for(var i=0;i<len;i++)
22                         {//把方格坐标转化为场景坐标
23                             var obj=path[i];
24                             obj[0]=(obj[0]-len_x/2)*len_s;
25                             obj[1]=(-obj[1]+len_y/2)*len_s;
26                         }
27                         path.push(MyGame.player.positiontogo);
28                         path.shift();//把第一个出发节点去掉
29                         MyGame.player.path_goto=path;//在使用时在生成高度
30                         console.log("生成路径,起点:["+_this.player.mesh.position.x+","+_this.player.mesh.position.z+"]" +
31                             ",终点:["+_this.player.positiontogo[0]+","+_this.player.positiontogo[1]+"]");
32                     }
33                 }

 

  那样,大家就马到功成的完毕了在WebGL场景中寻路的靶子,接下去可以品味修改pathfinding使之能依照分裂地貌开始展览加权寻路,以及控制八个单位展开寻路行为。

  

  

这篇小说将琢磨哪边在三个自定义的地点网格上进展简要的2D寻路,以及鲜明路径后怎么着运用基于物理引…

    
那篇小说将研商哪边在三个自定义的地面网格上拓展简要的2D寻路,以及明确路径后怎样使用基于物理引擎的移动格局使实体沿路径到达目标地址。读者供给事先对WebGL和Babylonjs知识有一部分叩问,能够参见小编摄像的WebGL入门摄像教程和翻译的法定入门文档,当然也得以用本身喜好的任何方法来读书。

壹 、工具用法:

  作品首要分为如下几某个:

  小说首要分为如下几局地:

1、访问 

  一 、自定义地面网格与寻路矩阵

  壹 、自定义地面网格与寻路矩阵

澳门葡京 6

  2、生成Babylon格式3D模型

  2、生成Babylon格式3D模型

在情景世界坐标系的(0,-10,0),(0,0,0),(0,10,0)处各有3个深青莲小球作为参考试场点,使用前后左右和鼠标拖动能够举办场景漫游。

  3、使用pathfinding库进行2D寻路

  3、使用pathfinding库进行2D寻路

贰 、按F12键打开Chrome控制台,在控制毕尔巴鄂输入:MakeRibbon(MakeRing(5,12),-10,2,11,”mesh_ribbon”)回车:

  ④ 、基于cannon.js物理引擎使物体沿路径移动

  ④ 、基于cannon.js物理引擎使实体沿路径移动

澳门葡京 7

  场景能够经过

  场景可以透过

在情景中绘制了三个半径为5,曲面细分度为12,左端位于-10,每多个圆环间距2,共由十一个圆环组成的圆柱面。

  场景如下图:

  场景如下图:

拉近查看:

澳门葡京 8

澳门葡京 9

澳门葡京 10

  使用WASD控制自由相机地点,移动鼠标控制视角,右键点击地面会在地头上放置2个“指标方块”,然后标有“农民”标志的小球会向目的方块移动。

  使用WASD控制自由相飞机地方置,移动鼠标控制视角,右键点击地面会在地头上停放一个“指标方块”,然后标有“农民”标志的小球会向目的方块移动。

3、输入ShowNormals(mesh_origin)将用革命线段显示每一个终端的法线方向

  场景中使用了2DA*寻路算法,如下图所示:

  场景中使用了2DA*寻路算法,如下图所示:

澳门葡京 11

澳门葡京 12

澳门葡京 13

输入DeleteMeshes([lines_normal]在WebGL场景中使用2DA,使用Chrome控制台实行3D模型编辑的品尝。)能够去除全数的法线,输入DeleteMeshes([mesh_origin])则删除圆柱面网格。

  当指标方块位于障碍的另多只时,农民会尽力而为寻找最短的路径绕开障碍物前往指标方块。

  当对象方块位于障碍的另贰只时,农民会尽也许寻找最短的路线绕开障碍物前往指标方块。

肆 、鼠标移入网格上的三角,会显得三角形的顶峰新闻:

① 、自定义地面网格与寻路矩阵:

① 、自定义地面网格与寻路矩阵:

澳门葡京 14

a、在Babylon.js渲染引擎中自定义地面网格

a、在Babylon.js渲染引擎中自定义地面网格

当中“1:2-5”表示那是三角形的第二个顶峰,这些终端位于索引是2的圆环上(第多个圆环),这几个极限在圆环中的目录是5(也正是第四个极端)。

 1     var vdata_ground=new BABYLON.VertexData.CreateGround({width:198,height:198,subdivisionsX:99,subdivisionsY:99});//分成了99段,一条边上100个顶点
 2     var arr_vposition=vdata_ground.positions;
 3     var map=[];
 4     var len=arr_vposition.length/3;//和挨个遍历比起来,似乎有目的的去找更好
 5     for(var i=20;i<81;i++)//对于这个范围内的行
 6     {
 7         for(var j=20;j<23;j++)//对于这个范围内的列
 8         {
 9             arr_vposition[(j+100*i)*3+1]=1;
10         }
11     }
12     for(var i=20;i<81;i++)//对于这个范围内的行
13     {
14         for(var j=40;j<43;j++)//对于这个范围内的列
15         {
16             arr_vposition[(j+100*i)*3+1]=2;
17         }
18     }
19     for(var i=20;i<81;i++)//对于这个范围内的行
20     {
21         for(var j=60;j<63;j++)//对于这个范围内的列
22         {
23             arr_vposition[(j+100*i)*3+1]=4;
24         }
25     }
26     BABYLON.VertexData._ComputeSides(0, arr_vposition, vdata_ground.indices, vdata_ground.normals
27         , vdata_ground.uvs);
28     var mesh_ground=new BABYLON.Mesh("mesh_ground",scene);
29     mesh_ground.renderingGroupId=2;
30     vdata_ground.applyToMesh(mesh_ground, true);
 1     var vdata_ground=new BABYLON.VertexData.CreateGround({width:198,height:198,subdivisionsX:99,subdivisionsY:99});//分成了99段,一条边上100个顶点
 2     var arr_vposition=vdata_ground.positions;
 3     var map=[];
 4     var len=arr_vposition.length/3;//和挨个遍历比起来,似乎有目的的去找更好
 5     for(var i=20;i<81;i++)//对于这个范围内的行
 6     {
 7         for(var j=20;j<23;j++)//对于这个范围内的列
 8         {
 9             arr_vposition[(j+100*i)*3+1]=1;
10         }
11     }
12     for(var i=20;i<81;i++)//对于这个范围内的行
13     {
14         for(var j=40;j<43;j++)//对于这个范围内的列
15         {
16             arr_vposition[(j+100*i)*3+1]=2;
17         }
18     }
19     for(var i=20;i<81;i++)//对于这个范围内的行
20     {
21         for(var j=60;j<63;j++)//对于这个范围内的列
22         {
23             arr_vposition[(j+100*i)*3+1]=4;
24         }
25     }
26     BABYLON.VertexData._ComputeSides(0, arr_vposition, vdata_ground.indices, vdata_ground.normals
27         , vdata_ground.uvs);
28     var mesh_ground=new BABYLON.Mesh("mesh_ground",scene);
29     mesh_ground.renderingGroupId=2;
30     vdata_ground.applyToMesh(mesh_ground, true);

5、输入PickPoints([[2,5],[3,5],[2,6]],mesh_origin)能够选定那些极端

   第壹行创设了贰个Ground类型的Babylonjs“顶点数据”对象,这几个目的涵盖了建立地点网格所需的终端地方、法线、纹理坐标、顶点索引数据(建议读者亲自用调试形式看一下以此目的的结构),构造函数中的七个198意味当地的长度宽度是198,三个99表示每一条边被分成99段(由九十六个极端组成,每八个终端之间的偏离为2),至于怎么设置为99段后文仲有表达,这时的地面网格要是渲染出来将是贰个平面。

   第叁行创设了3个Ground类型的Babylonjs“顶点数据”对象,这么些目的涵盖了建立地点网格所需的顶点地点、法线、纹理坐标、顶点索引数据(提出读者亲自用调试情势看一下以此目的的组织),构造函数中的三个198代表当地的长宽是198,五个99意味着每一条边被分成99段(由玖十五个顶峰组成,每七个顶峰之间的距离为2),至于为啥设置为99段后文子禽有表明,那时的地面网格借使渲染出来将是三个平面。

澳门葡京 15

  要让地面变得坑坑洼洼有三种思路:在中度变化的点的比例较大时,能够尝尝对各样终端进行遍历,然后依照某种规则变更顶点的可观;在比例较小时建议直接在缓存数组中找到这一个极端实行更改,显著后者速度更快。

  要让本地变得湿魂洛魄有三种思路:在高度变化的点的比重较大时,可以尝试对每一个终端举办遍历,然后根据某种规则改变顶点的惊人;在比例较时辰提出直接在缓存数组中找到这个极端进行转移,显著后者速度更快。

被入选顶点所影响的具有边框线标示为黄绿,这些“选中”只是改变外观而已。

  第①6行依据顶点数据对种种面包车型地铁正面与反面举办测算,在对网格的顶峰新闻进行改动后一般都要实施这一条语句,而另一条平时在它后面实施的口舌是:“

  第一6行依照顶点数据对种种面的正面与反面实行总计,在对网格的顶峰新闻实行改动后一般都要进行这一条语句,而另一条通常在它后边实施的言语是:“

6、输入TransVertex(mesh_origin,arr_ij,BABYLON.Matrix.Translation(0,0,-10))将所选的顶点向z轴负方向移动10,被活动的顶峰和后边选中的顶峰其实远非提到,当中arr_ij也得以直接用索引数组[[2,5],[3,5],[2,6]]代替。

BABYLON.VertexData.ComputeNormals(positions, indices, normals);
BABYLON.VertexData.ComputeNormals(positions, indices, normals);

澳门葡京 16

”,它的功能是在巅峰数据变化后再次总括法线方向。那里不履行那条语句的因由是贝布ylonjs中的地面网格是一种“简化”的网格

”,它的功能是在巅峰数据变动后重新总计法线方向。那里不进行那条语句的缘故是Babylonjs中的地面网格是一种“简化”的网格

另一类变形能够通过输入:TransVertex(mesh_origin,arr_ij,BABYLON.Matrix.RotationX(Math.PI/2))达成,那能够把被入选的顶点绕X中旋转90度。

  如图所示:

  如图所示:

输入DeleteMeshes([lines_inpicked])裁撤被选中的功能,输入ChangeMaterial(mesh_origin,mat_blue)将边框换到日光黄纹理:

澳门葡京 17

澳门葡京 18

澳门葡京 19

  同样表示三个方块,简化的办法接纳三个终端,顶点之间的片元数据由顶点数据插值而成,因为右边的方框和左边的方框共用了八个极点,所以那八个方块的法线方向和纹理坐标必定是接连的。而用非简化的章程意味着那多少个方块,则需求选择八个顶峰,缺点是增多了对质量的消耗,优点是法线方向和纹理坐标不必总是,能够举行完全分裂的转变。

  同样表示八个方块,简化的方法接纳七个终端,顶点之间的片元数据由顶点数据插值而成,因为左侧的正方和右手的四方共用了五个极点,所以那七个方块的法线方向和纹理坐标必定是接连的。而用非简化的主意意味着这五个方块,则供给动用多个顶峰,缺点是充实了对质量的损耗,优点是法线方向和纹理坐标不必总是,能够拓展完全区别的变更。

能够见见变形后的效用,接下去仍是能够继续选用顶点并变形

  因为运用了简化的不二法门,地面网格的同二个终极处于八个例外的平面中,使用ComputeNormals总结地面网格的顶峰的法线方向也就失去了意义,事实上Babylonjs把地方网格顶点的法线方向都暗中同意为竖直向上。

  因为使用了简化的艺术,地面网格的同1个终极处于多个区别的平面中,使用ComputeNormals总计地面网格的终极的法线方向也就错过了意思,事实上Babylonjs把地点网格顶点的法线方向都默许为竖直向上。

7、输入ExportMesh(“1”,mat_blue),以txt格式导出babylon模型文件,文件名为“1.txt”

  前边的代码建立了贰个空的网格,将网格的渲染组织设立为2,将顶点数据提交这些空网格对象。

  前边的代码建立了贰个空的网格,将网格的渲染组织设立为2,将顶点数据交由这一个空网格对象。

澳门葡京 20

  生成的网格如下图所示:

  生成的网格如下图所示:

 ⑧ 、将导出的txt改名为9.babylon后放入网站目录中,访问

澳门葡京 21

澳门葡京 22

贰 、编制程序思路:

 

 

1、首先要确立2个能够开始展览各类测试的根底场景,使用的代码如下:

b、建立2D寻路矩阵

b、建立2D寻路矩阵

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>建立一个条带网格生成器,能够输入参数生成起始条带,然后通过命令行选取并修改pathArray,最后导出生成的条带</title>
  6     <link href="../CSS/newland.css" rel="stylesheet">
  7     <link href="../CSS/stat.css" rel="stylesheet">
  8     <script src="../JS/MYLIB/Events.js"></script>
  9     <script src="../JS/MYLIB/FileText.js"></script>
 10     <script src="../JS/MYLIB/View.js"></script>
 11     <script src="../JS/LIB/babylon.32.all.maxs.js"></script><!--V3.2的稳定版本-->
 12     <script src="../JS/MYLIB/newland.js"></script>
 13     <script src="../JS/LIB/stat.js"></script>
 14 </head>
 15 <body>
 16 <div id="div_allbase">
 17     <canvas id="renderCanvas"></canvas>
 18     <div id="fps" style="z-index: 301;"></div>
 19 </div>
 20 </body>
 21 <script>
 22     var VERSION=1.0,AUTHOR="lz_newland@163.com";
 23     var machine,canvas,engine,scene,gl,MyGame={};
 24     canvas = document.getElementById("renderCanvas");
 25     engine = new BABYLON.Engine(canvas, true);
 26     gl=engine._gl;//可以结合使用原生OpenGL和Babylon.js;
 27     scene = new BABYLON.Scene(engine);
 28     var divFps = document.getElementById("fps");
 29 
 30     window.onload=beforewebGL;
 31     function beforewebGL()
 32     {
 33         if(engine._webGLVersion==2.0)//输出ES版本
 34         {
 35             console.log("ES3.0");
 36         }
 37         else{
 38             console.log("ES2.0");
 39         }
 40         //MyGame=new Game(0,"first_pick","","http://127.0.0.1:8082/");
 41         /*0-startWebGL
 42          * */
 43         webGLStart();
 44     }
 45     //从下面开始分成简单测试和对象框架两种架构
 46     //简单测试
 47     //全局对象
 48     var light0//全局光源
 49             ,camera0//主相机
 50             ;
 51     //四种常用材质
 52     var mat_frame = new BABYLON.StandardMaterial("mat_frame", scene);
 53     mat_frame.wireframe = true;
 54     var mat_red = new BABYLON.StandardMaterial("mat_red", scene);
 55     mat_red.diffuseColor = new BABYLON.Color3(1, 0, 0);
 56     mat_red.backFaceCulling=false;
 57     var mat_green = new BABYLON.StandardMaterial("mat_green", scene);
 58     mat_green.diffuseColor = new BABYLON.Color3(0, 1, 0);
 59     mat_green.backFaceCulling=false;
 60     var mat_blue = new BABYLON.StandardMaterial("mat_blue", scene);
 61     mat_blue.diffuseColor = new BABYLON.Color3(0, 0, 1);
 62     mat_blue.backFaceCulling=false;
 63     var mesh_origin;
 64     var advancedTexture=BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("ui1");//全屏GUI
 65     function webGLStart()
 66     {
 67         window.addEventListener("resize", function () {//自动调整视口尺寸
 68             engine.resize();
 69         });
 70         camera0 =new BABYLON.FreeCamera("FreeCamera", new BABYLON.Vector3(0, 0, -80), scene);
 71         camera0.attachControl(canvas, true);
 72         camera0.speed=0.5;//相机移动速度是默认速度的一半
 73         camera0.minZ=0.01;//相机位置距前视锥截面的距离,也就是说到相机距离小于0.01的图元都不会显示,这个值不能过小,否则Babylon.js内置的鼠标选取将失效
 74         camera0.layerMask=2;//相机的遮罩层次,这个相机将只能显示遮罩层次同为2的网格,如果不设置这个属性,似乎可以显示所有遮罩层次的网格
 75         scene.activeCameras.push(camera0);//将相机加入活跃相机列表,默认情况下Babylon.js只使用一个活跃相机,但是也可以强行使用多个
 76         light0 = new BABYLON.HemisphericLight("Hemi0", new BABYLON.Vector3(0, 1, 0), scene);//半球光源
 77      //三个参照物,MeshBuilder是新版Babylon.js中使用的网格构建对象,之前翻译入门教程时还没有这个对象,它的特点是把一大堆参数统一整理到一个option参数中
 78         var mesh_base=new BABYLON.MeshBuilder.CreateSphere("mesh_base",{diameter:1},scene);
 79         mesh_base.material=mat_green;
 80         mesh_base.position.x=0;
 81         mesh_base.layerMask=2;
 82         var mesh_base1=new BABYLON.MeshBuilder.CreateSphere("mesh_base1",{diameter:1},scene);
 83         mesh_base1.position.y=10;
 84         mesh_base1.position.x=0;
 85         mesh_base1.material=mat_green;
 86         mesh_base1.layerMask=2;
 87         var mesh_base2=new BABYLON.MeshBuilder.CreateSphere("mesh_base2",{diameter:1},scene);
 88         mesh_base2.position.y=-10;
 89         mesh_base2.position.x=0;
 90         mesh_base2.material=mat_green;
 91         mesh_base2.layerMask=2;
 92       。
 93       。
 94       。
 95         MyBeforeRender();
 96     }
 97     function MyBeforeRender()
 98     {
 99         scene.registerBeforeRender(function() {
100             if(scene.isReady())
101             {
102                 。
103                 。
104                 。
105                 。
106                 。
107                 。
108             }
109         });
110         engine.runRenderLoop(function () {
111             engine.hideLoadingUI();
112             if (divFps) {
113                 // Fps
114                 divFps.innerHTML = engine.getFps().toFixed() + " fps";
115             }
116             scene.render();
117         });
118 
119     } 
120 </script>
121 </html>   

  在寻路场景中央银行使的pathfinding库必要用2个矩阵(二维数组)来定义障碍物的岗位,当中零成分表示这么些地块能够通行,不为零的要素表表示情爱莫能助通达,下边是树立这些数组的章程:

  在寻路场景中央银行使的pathfinding库须求用1个矩阵(二维数组)来定义障碍物的岗位,在那之中零成分表示那些地块能够畅通无阻,不为零的要素表示无能为力通达,上面是起家那些数组的点子:

其一3D场景包涵了大致测试所供给的一对着力成分,那里运用的是富含全部零部件的未压缩版Babylon.js库,在其实使用初级中学毕业生升学考试虑到节省带宽,能够应用Babylon.js官网提供的工具定制精简版或压缩版的Babylon.js库

 1     mesh_ground.mydata={};
 2     mesh_ground.mydata.walkabilityMatrix=MakewalkabilityMatrix(arr_vposition,99,99,2);
 3     mesh_ground.mydata.len_x=99;
 4     mesh_ground.mydata.len_y=99;
 5     mesh_ground.mydata.len_s=2;
 6     
 7     。
 8     。
 9     。
10     
11 //对每个正方形区块的倾斜程度进行计算,得出是否可以通行
12 //顶点数据,寻路空间宽度,寻路空间高度,每个方格区域的边长
13 function MakewalkabilityMatrix(arr,len_x,len_y,len_s)
14 {
15     var arr_Matrix=numeric.rep([len_y,len_x],0);
16     var len_s2=len_s*0.707;//求得平均点到其中一个边线点的水平距离0.7071067811865476
17     //var len_s2a=len_s2;
18     //var len_s2b=len_s2;
19     //var len_s2c=len_s2;
20     for(var i=0;i<len_y;i++)//对于每一行寻路单元格
21     {
22         for(var j=0;j<len_x;j++)//对于这一行里的每一个单元格
23         {
24             var int1=j+i*(len_x+1);
25             var int2=j+i*(len_x+1)+1;
26             var int3=j+(i+1)*(len_x+1);
27             var int4=j+(i+1)*(len_x+1)+1;
28             var y1=arr[int1*3+1];
29             var y2=arr[int2*3+1];
30             var y3=arr[int3*3+1];
31             var y4=arr[int4*3+1];
32             var ya=(y1+y2+y3+y4)/4;
33             var yb=Math.max(Math.abs(y1-ya),Math.abs(y2-ya),Math.abs(y3-ya),Math.abs(y4-ya));
34             arr_Matrix[i][j]=parseInt((yb)/0.707);//高度超过了水平距离几倍就认为是几倍的障碍物
35         }
36     }
37     return arr_Matrix;
38 }
 1     mesh_ground.mydata={};
 2     mesh_ground.mydata.walkabilityMatrix=MakewalkabilityMatrix(arr_vposition,99,99,2);
 3     mesh_ground.mydata.len_x=99;
 4     mesh_ground.mydata.len_y=99;
 5     mesh_ground.mydata.len_s=2;
 6     
 7     。
 8     。
 9     。
10     
11 //对每个正方形区块的倾斜程度进行计算,得出是否可以通行
12 //顶点数据,寻路空间宽度,寻路空间高度,每个方格区域的边长
13 function MakewalkabilityMatrix(arr,len_x,len_y,len_s)
14 {
15     var arr_Matrix=numeric.rep([len_y,len_x],0);
16     var len_s2=len_s*0.707;//求得平均点到其中一个边线点的水平距离0.7071067811865476
17     //var len_s2a=len_s2;
18     //var len_s2b=len_s2;
19     //var len_s2c=len_s2;
20     for(var i=0;i<len_y;i++)//对于每一行寻路单元格
21     {
22         for(var j=0;j<len_x;j++)//对于这一行里的每一个单元格
23         {
24             var int1=j+i*(len_x+1);
25             var int2=j+i*(len_x+1)+1;
26             var int3=j+(i+1)*(len_x+1);
27             var int4=j+(i+1)*(len_x+1)+1;
28             var y1=arr[int1*3+1];
29             var y2=arr[int2*3+1];
30             var y3=arr[int3*3+1];
31             var y4=arr[int4*3+1];
32             var ya=(y1+y2+y3+y4)/4;
33             var yb=Math.max(Math.abs(y1-ya),Math.abs(y2-ya),Math.abs(y3-ya),Math.abs(y4-ya));
34             arr_Matrix[i][j]=parseInt((yb)/0.707);//高度超过了水平距离几倍就认为是几倍的障碍物
35         }
36     }
37     return arr_Matrix;
38 }

② 、建立贰个基础网格

  这一段代码的思路是:将本地网格垂直方向的正投影作为寻路单元格,取每多个寻路单元格的八个极端,算出那多个极端的平分高度与各种终端中度的差的最大值与寻路单元格宗旨点到顶点的水准距离的比,将以此比率作为“障碍程度”(简单来说正是终点高度变化的游春戏烈,障碍就越难跨越)。然后为网格添加2个mydata属性(JavaScript语言的优势),把和寻路矩阵有关的音信放到那个天性里。

  这一段代码的笔触是:将当地网格垂直方向的正投影作为寻路单元格,取每2个寻路单元格的多少个终端,算出那八个终端的平均中度与各类终端中度的差的最大值与寻路单元格宗旨点到终极的档次距离的比,将以此比率作为“障碍程度”(不难的话正是极限高度变化的越剧烈,障碍就越难跨越)。然后为网格添加一个mydata属性(JavaScript语言的优势),把和寻路矩阵有关的音信放到那么些本性里。

安排经过对一个基础网格开始展览极端变换到发出种种各个的简便模型,在贝布ylon.js中“条带”是一种相当适合顶点变换的网格类型,Babylon.js官方教程中有有关条带构造和变形的文书档案,能够在此地下载汉译

  那里运用了numeric数学库,能够在

  那里运用了numeric数学库,能够在

用来建立基础网格的代码如下:

  2、生成babylon格式的3D模型:

  2、生成babylon格式的3D模型:

 1     //下面这些函数都通过控制台调用
 2     //在ZoY平面里建立一个圆环路径
 3     //radius:半径,sumpoint:使用几个点
 4     function MakeRing(radius,sumpoint)
 5     {
 6         var arr_point=[];
 7         var radp=Math.PI*2/sumpoint;
 8         for(var i=0.0;i<sumpoint;i++)
 9         {
10             var x=0;
11             var rad=radp*i;
12             //var y=sswr(radius*Math.sin(rad),null,5);//在这里需要降低一些精确度?否则Babylon.js在计算顶点数据时可能和这里不一致?
13             //var z=sswr(radius*Math.cos(rad),null,5);
14             var y=radius*Math.sin(rad);
15             var z=radius*Math.cos(rad);
16             arr_point.push(new BABYLON.Vector3(x,y,z));
17         }
18         arr_point.push(arr_point[0].clone());//首尾相连,不能这样相连,否则变形时会多出一个顶点!!,看来这个多出的顶点无法去掉,只能在选取时额外处理它
19         return arr_point;
20     }
21     var arr_path=[];//核心数据
22     //arr_point:单个路径的点数组,xstartl:第一个扁平路径放在最左侧,spacing:路径的间距,sumpath:一共使用几条路径,
23     function MakeRibbon(arr_point,xstartl,spacing,sumpath,name)
24     {//将一条圆环路径扩展成相互平行的多个圆环路径,然后使用这些路径生成条带
25         arr_path=[];
26         for(var i=0;i<sumpath;i++)//对于每一条路径
27         {
28             var x=xstartl+spacing*i;
29             //var arr=arr_point.concat(null);//为什么拷贝失灵了?
30             //var [ ...arr ] = arr_point;//ES6的新扩展运算符?-》也不好使,因为数组里的元素是指针?!!
31             var len=arr_point.length;
32             var arr=[];
33             for(var j=0;j<len;j++)
34             {
35                 var obj=arr_point[j].clone();
36                 obj.x=x;
37                 //
38                 arr.push(obj);
39             }
40             arr_path.push(arr);
41             arr=null;
42         }
43         mesh_origin.dispose();
44         mesh_origin=BABYLON.MeshBuilder.CreateRibbon(name,{pathArray:arr_path,updatable:true,closePath:false,closeArray:false});
45         //mesh_origin=mesh;//用一个全局变量保存最终会被导出的mesh
46         mesh_origin.sideOrientation=BABYLON.Mesh.DOUBLESIDE;//显示网格的前后两面
47         mesh_origin.material=mat_frame;
48         mesh_origin.layerMask=2;
49     }

  网格生成终结后需求获得任何程序中选用,那里笔者选拔把它保存为babylon格式的3D模型,babylon是一种json字符串模型文件,其独到之处是构造简单意义完善。

  网格生成终结后要求得到别的程序中利用,那里笔者选择把它保存为babylon格式的3D模型,babylon是一种json字符串模型文件,其亮点是构造简单意义周详。

编程中遇到的多少个难点:

  Babylon.js的官方网站上有完整的格式表明和例子:

  Babylon.js的官方网站上有完整的格式表明和例子:

a、路径中设置的坐标值在实际上突显时可能发生轻微的变更,比如5大概变成4.999999999999999999,不过如同没什么影响。

  以下是转变对应json的代码:

  以下是生成对应json的代码:

b、就算圆环路径分成12段应该由10个极点组成,不过一旦唯有13个极点,那么在调用CreateRibbon方法时,假使把closePath参数设为true则Babylon.js会自动抬高二个不受控制的巅峰来闭合圆环路径,假若设为false,则路径不可能闭合。为此在第①8行再添加二个与开始点

  1 /**
  2  * Created by Administrator on 2017/7/14.
  3  */
  4 function Export_mesh(arr_mesh,PngName)//用Babylon格式导出模型
  5 {
  6     //场景对象
  7     var obj_scene=
  8     {
  9         'autoClear': true,
 10         'clearColor': [0,0,0],
 11         'ambientColor': [0,0,0],
 12         'gravity': [0,-9.81,0],
 13         'cameras': [{
 14             'name': 'Camera',
 15             'id': 'Camera',
 16             'position': [7.4811,5.3437,-6.5076],
 17             'target': [-0.3174,0.8953,0.3125],
 18             'fov': 0.8576,
 19             'minZ': 0.1,
 20             'maxZ': 100,
 21             'speed': 1,
 22             'inertia': 0.9,
 23             'checkCollisions': false,
 24             'applyGravity': false,
 25             'ellipsoid': [0.2,0.9,0.2]
 26         }],
 27         'activeCamera': 'Camera',
 28         'lights': [{
 29             'name': 'Sun',
 30             'id': 'Sun',
 31             'type': 1,
 32             'position': [0.926,7.3608,14.1829],
 33             'direction': [-0.347,-0.4916,-0.7987],
 34             'intensity': 1,
 35             'diffuse': [1,1,1],
 36             'specular': [1,1,1]
 37         }],
 38         'materials':[{
 39             'name': 'mball',
 40             'id': 'mball',
 41             'ambient': [1,1,1],
 42             'diffuse': [1,1,1],
 43             'specular': [1,1,1],
 44             'specularPower': 50,
 45             'emissive': [0,0,0],
 46             'alpha': 1,
 47             'backFaceCulling': true,
 48             'diffuseTexture': {
 49                 'name': PngName?PngName:'snow2.jpg',
 50                 'level': 1,
 51                 'hasAlpha': 1,
 52                 'coordinatesMode': 0,
 53                 'uOffset': 0,
 54                 'vOffset': 0,
 55                 'uScale': 1,
 56                 'vScale': 1,
 57                 'uAng': 0,
 58                 'vAng': 0,
 59                 'wAng': 0,
 60                 'wrapU': true,
 61                 'wrapV': true,
 62                 'coordinatesIndex': 0
 63             }
 64         }],
 65         'geometries': {},
 66         'meshes': [],
 67         'multiMaterials': [],
 68         'shadowGenerators': [],
 69         'skeletons': [],
 70         'sounds': [],
 71         'mydata':{'walkabilityMatrix':[]}
 72     };
 73     //所有模型组件的父物体
 74     var obj_allbase=
 75     {
 76         'name': 'allbase',
 77         'id': 'allbase',
 78         'materialId': 'mball',
 79         'position': [0,0,0],
 80         'rotation': [0,0,0],
 81         'scaling': [1,1,1],
 82         'isVisible': true,
 83         'isEnabled': true,
 84         'checkCollisions': false,
 85         'billboardMode': 0,
 86         'receiveShadows': true,
 87         'positions': [],
 88         'normals': [],
 89         'uvs': [],
 90         'indices': [],
 91         'subMeshes': [{
 92             'materialIndex': 0,
 93             'verticesStart': 0,
 94             'verticesCount': 0,
 95             'indexStart': 0,
 96             'indexCount': 0
 97         }]
 98     };
 99     obj_scene.meshes.push(obj_allbase);
100     var len=arr_mesh.length;
101     var all_x=0;
102     var all_y=0;
103     var all_z=0;
104     for(var i=0;i<len;i++)
105     {
106         var obj_child={};
107         if(arr_mesh[i].geometry._vertexBuffers!=null)
108         {
109             var child=arr_mesh[i];
110             if(!child.mydata)
111             {
112                 child.mydata={}
113             }
114             var vb=child.geometry._vertexBuffers;
115             all_x+=child.position.x;
116             all_y+=child.position.y;
117             all_z+=child.position.z;
118             obj_child=
119             {
120                 'name': child.name,
121                 'id': child.id,
122                 'parentID': 'allbase',
123                 'materialId': 'mball',
124                 'position': [child.position.x,child.position.y,child.position.z],
125                 'rotation': [child.rotation.x,child.rotation.y,child.rotation.z],
126                 'scaling': [child.scaling.x,child.scaling.y,child.scaling.z],
127                 'isVisible': true,
128                 'isEnabled': true,
129                 'checkCollisions': false,
130                 'billboardMode': 0,
131                 'receiveShadows': true,
132                 'positions': vb.position._buffer._data,
133                 'normals': vb.normal._buffer._data,
134                 'uvs': vb.uv._buffer._data,
135                 'indices': child.geometry._indices,
136                 'subMeshes': [{
137                     'materialIndex': 0,
138                     'verticesStart': 0,
139                     'verticesCount': vb.position._buffer._data.length,
140                     'indexStart': 0,
141                     'indexCount': child.geometry._indices.length
142                 }],
143                 'mydata':child.mydata
144             };
145             obj_scene.meshes.push(obj_child);
146         }
147     }
148     //不能让模型的主体过于偏离模型的中心
149     all_x=all_x/len;
150     all_y=all_y/len;
151     all_z=all_z/len;
152     for(var i=1;i<len+1;i++)
153     {
154         obj_scene.meshes[i].position[0]-=all_x;
155         obj_scene.meshes[i].position[1]-=all_y;
156         obj_scene.meshes[i].position[2]-=all_z;
157     }
158     var str_data=JSON.stringify(obj_scene);
159     DownloadText(MakeDateStr()+"testscene",str_data,".babylon");
160 }
  1 /**
  2  * Created by Administrator on 2017/7/14.
  3  */
  4 function Export_mesh(arr_mesh,PngName)//用Babylon格式导出模型
  5 {
  6     //场景对象
  7     var obj_scene=
  8     {
  9         'autoClear': true,
 10         'clearColor': [0,0,0],
 11         'ambientColor': [0,0,0],
 12         'gravity': [0,-9.81,0],
 13         'cameras': [{
 14             'name': 'Camera',
 15             'id': 'Camera',
 16             'position': [7.4811,5.3437,-6.5076],
 17             'target': [-0.3174,0.8953,0.3125],
 18             'fov': 0.8576,
 19             'minZ': 0.1,
 20             'maxZ': 100,
 21             'speed': 1,
 22             'inertia': 0.9,
 23             'checkCollisions': false,
 24             'applyGravity': false,
 25             'ellipsoid': [0.2,0.9,0.2]
 26         }],
 27         'activeCamera': 'Camera',
 28         'lights': [{
 29             'name': 'Sun',
 30             'id': 'Sun',
 31             'type': 1,
 32             'position': [0.926,7.3608,14.1829],
 33             'direction': [-0.347,-0.4916,-0.7987],
 34             'intensity': 1,
 35             'diffuse': [1,1,1],
 36             'specular': [1,1,1]
 37         }],
 38         'materials':[{
 39             'name': 'mball',
 40             'id': 'mball',
 41             'ambient': [1,1,1],
 42             'diffuse': [1,1,1],
 43             'specular': [1,1,1],
 44             'specularPower': 50,
 45             'emissive': [0,0,0],
 46             'alpha': 1,
 47             'backFaceCulling': true,
 48             'diffuseTexture': {
 49                 'name': PngName?PngName:'snow2.jpg',
 50                 'level': 1,
 51                 'hasAlpha': 1,
 52                 'coordinatesMode': 0,
 53                 'uOffset': 0,
 54                 'vOffset': 0,
 55                 'uScale': 1,
 56                 'vScale': 1,
 57                 'uAng': 0,
 58                 'vAng': 0,
 59                 'wAng': 0,
 60                 'wrapU': true,
 61                 'wrapV': true,
 62                 'coordinatesIndex': 0
 63             }
 64         }],
 65         'geometries': {},
 66         'meshes': [],
 67         'multiMaterials': [],
 68         'shadowGenerators': [],
 69         'skeletons': [],
 70         'sounds': [],
 71         'mydata':{'walkabilityMatrix':[]}
 72     };
 73     //所有模型组件的父物体
 74     var obj_allbase=
 75     {
 76         'name': 'allbase',
 77         'id': 'allbase',
 78         'materialId': 'mball',
 79         'position': [0,0,0],
 80         'rotation': [0,0,0],
 81         'scaling': [1,1,1],
 82         'isVisible': true,
 83         'isEnabled': true,
 84         'checkCollisions': false,
 85         'billboardMode': 0,
 86         'receiveShadows': true,
 87         'positions': [],
 88         'normals': [],
 89         'uvs': [],
 90         'indices': [],
 91         'subMeshes': [{
 92             'materialIndex': 0,
 93             'verticesStart': 0,
 94             'verticesCount': 0,
 95             'indexStart': 0,
 96             'indexCount': 0
 97         }]
 98     };
 99     obj_scene.meshes.push(obj_allbase);
100     var len=arr_mesh.length;
101     var all_x=0;
102     var all_y=0;
103     var all_z=0;
104     for(var i=0;i<len;i++)
105     {
106         var obj_child={};
107         if(arr_mesh[i].geometry._vertexBuffers!=null)
108         {
109             var child=arr_mesh[i];
110             if(!child.mydata)
111             {
112                 child.mydata={}
113             }
114             var vb=child.geometry._vertexBuffers;
115             all_x+=child.position.x;
116             all_y+=child.position.y;
117             all_z+=child.position.z;
118             obj_child=
119             {
120                 'name': child.name,
121                 'id': child.id,
122                 'parentID': 'allbase',
123                 'materialId': 'mball',
124                 'position': [child.position.x,child.position.y,child.position.z],
125                 'rotation': [child.rotation.x,child.rotation.y,child.rotation.z],
126                 'scaling': [child.scaling.x,child.scaling.y,child.scaling.z],
127                 'isVisible': true,
128                 'isEnabled': true,
129                 'checkCollisions': false,
130                 'billboardMode': 0,
131                 'receiveShadows': true,
132                 'positions': vb.position._buffer._data,
133                 'normals': vb.normal._buffer._data,
134                 'uvs': vb.uv._buffer._data,
135                 'indices': child.geometry._indices,
136                 'subMeshes': [{
137                     'materialIndex': 0,
138                     'verticesStart': 0,
139                     'verticesCount': vb.position._buffer._data.length,
140                     'indexStart': 0,
141                     'indexCount': child.geometry._indices.length
142                 }],
143                 'mydata':child.mydata
144             };
145             obj_scene.meshes.push(obj_child);
146         }
147     }
148     //不能让模型的主体过于偏离模型的中心
149     all_x=all_x/len;
150     all_y=all_y/len;
151     all_z=all_z/len;
152     for(var i=1;i<len+1;i++)
153     {
154         obj_scene.meshes[i].position[0]-=all_x;
155         obj_scene.meshes[i].position[1]-=all_y;
156         obj_scene.meshes[i].position[2]-=all_z;
157     }
158     var str_data=JSON.stringify(obj_scene);
159     DownloadText(MakeDateStr()+"testscene",str_data,".babylon");
160 }

臃肿的终极使圆环路径闭合。

  能够见见,3个babylon文件能够分包四个网格对象,除了网格对象之外那么些模型文件还能储存场景、光照、相机、动画、骨骼等信息,那些功用能够选择性使用。方法的终极动用DownloadText方法将json文本导出,DownloadText是作者参考网络资料编辑的字符下载方法,倘若不行使DownloadText,间接在Chrome浏览器的调节和测试方式下的一声令下行里输入“console.log(str_data)”也能获取json字符串。

  能够见到,贰个babylon文件能够包含多个网格对象,除了网格对象之外这些模型文件还是能够储存场景、光照、相机、动画、骨骼等消息,那几个功能能够选用性使用。方法的终极采纳DownloadText方法将json文本导出,DownloadText是作者参考互联网资料编辑的字符下载方法,若是不选择DownloadText,直接在Chrome浏览器的调节和测试格局下的指令行里输入“console.log(str_data)”也能获取json字符串。

c、原安顿一向行使数组的concat方法复制arr_point数组发生更加多的圆环路径,但concat方法如同只可以对一维数组使用(栈?),而arr_point的每一个成分都以一个BABYLON.Vector3对象,所以不得不用for循环贰个点七个点的浮动路径

  DownloadText内容如下:

  DownloadText内容如下:

d、MakeRing是1个生成圆环路径的艺术,使用者能够依据需求编写制定各类其余门类的路径生成方法。

澳门葡京 23澳门葡京 24

澳门葡京 25澳门葡京 26

三 、调整网格的习性:

  1 /**
  2  * Created by Administrator on 2015/3/2.
  3  */
  4 /**
  5  * 将指定字符写入指定名称的文本文件中,并可以选择本地保存目录,兼容IE11和谷歌浏览器
  6  */
  7 function DownloadText(filename,content,filetype)
  8 {
  9     if(filetype==null)
 10     {
 11         filetype=".txt";
 12     }
 13     if(document.createElement("a").download!=null)//谷歌和火狐
 14     {
 15         var aLink = document.createElement('a');
 16         var datatype="data:text/plain;charset=UTF-8,";
 17         if(filetype==".xml")
 18         {
 19             datatype="data:text/xml;charset=UTF-8,";
 20         }
 21         if(filetype==".babylon")
 22         {//浏览器还没有支持babylon的mime类型!!
 23             datatype="data:text/plain;charset=UTF-8,";
 24         }
 25         if(filetype==".png"||filetype==".jpeg")
 26         {
 27             datatype="";
 28         }
 29         if(content.length<1000000)
 30         {
 31             aLink.href = datatype+content;//dataurl格式的字符串"
 32         }
 33         else
 34         {//对于过大的文件普通dataURL不支持,所以使用“二进制流大对象”
 35             aLink.href=URL.createObjectURL(new Blob([content],{type:"text/plain"}));
 36         }
 37         aLink.download = filename;
 38         aLink.innerHTML=filename;
 39         //aLink.setAttribute("onclick","");
 40         aLink.onclick=function()
 41         {
 42             document.getElementById("div_choose").style.display="none";
 43             //delete_div('div_choose');
 44             delete_div('div_mask');
 45         }
 46         //aLink.style.display="none";
 47         //document.body.appendChild(aLink);
 48         /*var evt = document.createEvent("HTMLEvents");//建立一个事件
 49         evt.initEvent("click", false, false);//这是一个单击事件
 50         evt.eventType = 'message';
 51         aLink.dispatchEvent(evt);//触发事件*/
 52         //chrome认为点击超链接下载文件是超链接标签的“默认属性”,谷歌认为默认属性不可以用脚本来触发,所以从M53版本开始dispatchEvent无法触发超链接下载
 53         //window.open(datatype+content, "_blank");
 54         //document.write(datatype+content);
 55         delete_div('div_choose');
 56         delete_div('div_mask');
 57         var evt=evt||window.event;
 58         cancelPropagation(evt);
 59         var obj=evt.currentTarget?evt.currentTarget:evt.srcElement;
 60 
 61         Open_div("", "div_choose", 240, 180, 400, 80, "", "",1,401);//打开一个带遮罩的弹出框
 62         var div_choose=$("#div_choose")[0];
 63         div_choose.style.border="1px solid";
 64         div_choose.innerHTML="谷歌浏览器专用文件生成完毕,请点击下面的文件名下载文件。<br>"
 65         div_choose.appendChild(aLink);
 66         drag(div_choose);//让弹出框可以被拖拽
 67         aLink.onmousedown=function()
 68         {
 69             var evt=evt||window.event;
 70             cancelPropagation(evt);
 71         }
 72     }
 73     else//IE
 74     {
 75         var Folder=BrowseFolder();
 76         if(Folder=="false")
 77         {
 78             alert("保存失败!");
 79         }
 80         else
 81         {
 82             var fso, tf;
 83             fso = new ActiveXObject("Scripting.FileSystemObject");//创建文件系统对象
 84             tf = fso.CreateTextFile(Folder + filename+filetype, true,true);//创建一个文件
 85             tf.write(content);
 86             tf.Close();
 87             alert("保存完毕!");
 88         }
 89     }
 90 }
 91 function BrowseFolder()
 92 {//使用ActiveX控件
 93     try
 94     {
 95         var Message = "请选择保存文件夹";  //选择框提示信息
 96         var Shell = new ActiveXObject( "Shell.Application" );
 97         var Folder = Shell.BrowseForFolder(0,Message,0x0040,0x11);//起始目录为:我的电脑
 98         //var Folder = Shell.BrowseForFolder(0,Message,0); //起始目录为:桌面//选择桌面会报错!!
 99 
100         if(Folder != null)
101         {
102             Folder = Folder.items();  // 返回 FolderItems 对象
103             Folder = Folder.item();  // 返回 Folderitem 对象
104             Folder = Folder.Path;   // 返回路径
105             if(Folder.charAt(Folder.length-1) != "\\")
106             {
107                  Folder = Folder + "\\";
108             }
109             //document.all.savePath.value=Folder;
110             return Folder;
111         }
112     }
113     catch(e)
114     {
115         return "false";
116         alert(e.message);
117     }
118 }
  1 /**
  2  * Created by Administrator on 2015/3/2.
  3  */
  4 /**
  5  * 将指定字符写入指定名称的文本文件中,并可以选择本地保存目录,兼容IE11和谷歌浏览器
  6  */
  7 function DownloadText(filename,content,filetype)
  8 {
  9     if(filetype==null)
 10     {
 11         filetype=".txt";
 12     }
 13     if(document.createElement("a").download!=null)//谷歌和火狐
 14     {
 15         var aLink = document.createElement('a');
 16         var datatype="data:text/plain;charset=UTF-8,";
 17         if(filetype==".xml")
 18         {
 19             datatype="data:text/xml;charset=UTF-8,";
 20         }
 21         if(filetype==".babylon")
 22         {//浏览器还没有支持babylon的mime类型!!
 23             datatype="data:text/plain;charset=UTF-8,";
 24         }
 25         if(filetype==".png"||filetype==".jpeg")
 26         {
 27             datatype="";
 28         }
 29         if(content.length<1000000)
 30         {
 31             aLink.href = datatype+content;//dataurl格式的字符串"
 32         }
 33         else
 34         {//对于过大的文件普通dataURL不支持,所以使用“二进制流大对象”
 35             aLink.href=URL.createObjectURL(new Blob([content],{type:"text/plain"}));
 36         }
 37         aLink.download = filename;
 38         aLink.innerHTML=filename;
 39         //aLink.setAttribute("onclick","");
 40         aLink.onclick=function()
 41         {
 42             document.getElementById("div_choose").style.display="none";
 43             //delete_div('div_choose');
 44             delete_div('div_mask');
 45         }
 46         //aLink.style.display="none";
 47         //document.body.appendChild(aLink);
 48         /*var evt = document.createEvent("HTMLEvents");//建立一个事件
 49         evt.initEvent("click", false, false);//这是一个单击事件
 50         evt.eventType = 'message';
 51         aLink.dispatchEvent(evt);//触发事件*/
 52         //chrome认为点击超链接下载文件是超链接标签的“默认属性”,谷歌认为默认属性不可以用脚本来触发,所以从M53版本开始dispatchEvent无法触发超链接下载
 53         //window.open(datatype+content, "_blank");
 54         //document.write(datatype+content);
 55         delete_div('div_choose');
 56         delete_div('div_mask');
 57         var evt=evt||window.event;
 58         cancelPropagation(evt);
 59         var obj=evt.currentTarget?evt.currentTarget:evt.srcElement;
 60 
 61         Open_div("", "div_choose", 240, 180, 400, 80, "", "",1,401);//打开一个带遮罩的弹出框
 62         var div_choose=$("#div_choose")[0];
 63         div_choose.style.border="1px solid";
 64         div_choose.innerHTML="谷歌浏览器专用文件生成完毕,请点击下面的文件名下载文件。<br>"
 65         div_choose.appendChild(aLink);
 66         drag(div_choose);//让弹出框可以被拖拽
 67         aLink.onmousedown=function()
 68         {
 69             var evt=evt||window.event;
 70             cancelPropagation(evt);
 71         }
 72     }
 73     else//IE
 74     {
 75         var Folder=BrowseFolder();
 76         if(Folder=="false")
 77         {
 78             alert("保存失败!");
 79         }
 80         else
 81         {
 82             var fso, tf;
 83             fso = new ActiveXObject("Scripting.FileSystemObject");//创建文件系统对象
 84             tf = fso.CreateTextFile(Folder + filename+filetype, true,true);//创建一个文件
 85             tf.write(content);
 86             tf.Close();
 87             alert("保存完毕!");
 88         }
 89     }
 90 }
 91 function BrowseFolder()
 92 {//使用ActiveX控件
 93     try
 94     {
 95         var Message = "请选择保存文件夹";  //选择框提示信息
 96         var Shell = new ActiveXObject( "Shell.Application" );
 97         var Folder = Shell.BrowseForFolder(0,Message,0x0040,0x11);//起始目录为:我的电脑
 98         //var Folder = Shell.BrowseForFolder(0,Message,0); //起始目录为:桌面//选择桌面会报错!!
 99 
100         if(Folder != null)
101         {
102             Folder = Folder.items();  // 返回 FolderItems 对象
103             Folder = Folder.item();  // 返回 Folderitem 对象
104             Folder = Folder.Path;   // 返回路径
105             if(Folder.charAt(Folder.length-1) != "\\")
106             {
107                  Folder = Folder + "\\";
108             }
109             //document.all.savePath.value=Folder;
110             return Folder;
111         }
112     }
113     catch(e)
114     {
115         return "false";
116         alert(e.message);
117     }
118 }

能够对网格的质量实行部分调整,然而那一个调动只在这一个编辑器里生效,并不会被导出。

View Code

View Code

比如对网格材料的调动:

  接下去,咱们要在另3个主次中选取方不熟悉成的模子文件,使用Babylonjs的财富管理器加载网格:

  接下去,我们要在另三个程序中运用方面生成的模型文件,使用Babylonjs的财富管理器加载网格:

1 function ChangeMaterial(mesh,mat)
2     {
3         mesh.material=mat;
4     }
 1     this.loader =  new BABYLON.AssetsManager(this.scene);//资源管理器
 2 
 3     // 资源数组
 4     this.assets = {};
 5     //为资源管理器分配一个任务
 6     var meshTask = this.loader.addMeshTask("gun", "", "./assets/", "gun.babylon");
 7     meshTask.onSuccess = function(task) {//这个任务完成
 8         _this._initMesh(task);
 9     };    
//第一个参数表示task的name,第二个参数表示加载模型文件中的哪个网格,为空则用数组形式加载全部,第三个参数表示路径,第四个参数是文件名
10     var meshTask2 = this.loader.addMeshTask("mesh_ground", "", "./assets/arena/", "2017810_14_12_59testscene.babylon");
11     meshTask2.onSuccess = function(task) {
12         _this._initMesh(task);
13     };
14 
15     this.loader.onFinish = function (tasks)//所有任务完成
16     {
17     。。。
18     }
19     
20     。
21     。
22     。
23     
24     _initMesh : function(task)
25     {
26         this.assets[task.name] = task.loadedMeshes;
27         for (var i=0; i<task.loadedMeshes.length; i++ ){
28             var mesh = task.loadedMeshes[i];
29             mesh.isVisible = false;
30             //预先把所有资源加载下来,但不显示,当需要时再把它显示在需要的位置,或者在需要的位置,建立一个资源的实例(克隆)
31         }
32     }
33     
 1     this.loader =  new BABYLON.AssetsManager(this.scene);//资源管理器
 2 
 3     // 资源数组
 4     this.assets = {};
 5     //为资源管理器分配一个任务
 6     var meshTask = this.loader.addMeshTask("gun", "", "./assets/", "gun.babylon");
 7     meshTask.onSuccess = function(task) {//这个任务完成
 8         _this._initMesh(task);
 9     };    
//第一个参数表示task的name,第二个参数表示加载模型文件中的哪个网格,为空则用数组形式加载全部,第三个参数表示路径,第四个参数是文件名
10     var meshTask2 = this.loader.addMeshTask("mesh_ground", "", "./assets/arena/", "2017810_14_12_59testscene.babylon");
11     meshTask2.onSuccess = function(task) {
12         _this._initMesh(task);
13     };
14 
15     this.loader.onFinish = function (tasks)//所有任务完成
16     {
17     。。。
18     }
19     
20     。
21     。
22     。
23     
24     _initMesh : function(task)
25     {
26         this.assets[task.name] = task.loadedMeshes;
27         for (var i=0; i<task.loadedMeshes.length; i++ ){
28             var mesh = task.loadedMeshes[i];
29             mesh.isVisible = false;
30             //预先把所有资源加载下来,但不显示,当需要时再把它显示在需要的位置,或者在需要的位置,建立一个资源的实例(克隆)
31         }
32     }
33     

④ 、突显网格顶点法线方向

  那时,会时有发生四个寻常:Babylonjs并不匡助大家夹带在mesh中的mydata属性。化解方法是在babylon.30.all.max.js的21272行附近修改:

  那时,会发生三个不成难题:Babylonjs并不扶助大家夹带在mesh中的mydata属性。解决措施是在babylon.30.all.max.js的21272行附近修改:

代码如下:

1             if (parsedMesh.metadata !== undefined) {
2                 mesh.metadata = parsedMesh.metadata;
3             }
4             if (parsedMesh.mydata !== undefined) {
5                 mesh.mydata = parsedMesh.mydata;
6             }    
1             if (parsedMesh.metadata !== undefined) {
2                 mesh.metadata = parsedMesh.metadata;
3             }
4             if (parsedMesh.mydata !== undefined) {
5                 mesh.mydata = parsedMesh.mydata;
6             }    
 1 var lines_normal={};
 2     /*ShowNormals(mesh_origin)
 3      DeleteMeshes([lines_normal]);
 4     * */
 5     //显示所有的顶点法线
 6     function ShowNormals(mesh)
 7     {
 8         //DeleteMeshes(arr_line_normal);
 9         if(lines_normal.dispose)
10         {
11             lines_normal.dispose();
12         }
13         //遍历顶点
14         var vb=mesh.geometry._vertexBuffers;
15         var data_pos=vb.position._buffer._data;//顶点数据
16         var data_mormal=vb.normal._buffer._data;//法线数据
17         var len=data_pos.length;
18         var lines=[];
19         for(var i=0;i<len;i+=3)
20         {//CreateLineSystem使用一个网格包含很多分立的线段(路径),CreateLines则是一条首尾相连的路径
21             //
22             var vec=new BABYLON.Vector3(data_pos[i],data_pos[i+1],data_pos[i+2]);
23             var vec2=vec.clone().add(new BABYLON.Vector3(data_mormal[i],data_mormal[i+1],data_mormal[i+2]).normalize().scale(1));
24             lines.push([vec,vec2]);
25         }
26         lines_normal=new BABYLON.MeshBuilder.CreateLineSystem("lines_normal",{lines:lines,updatable:false},scene);
27         lines_normal.color=new BABYLON.Color3(1, 0, 0);
28     }

  仿照metadata的写法加上对mydata的帮衬,当然,也得以考虑把mydata夹带到其它被mesh所帮助的质量里。

  仿照metadata的写法加上对mydata的援救,当然,也能够设想把mydata夹带到任何被mesh所补助的品质里。

Babylon.js内置的CreateLineSystem方法能够便宜的树立多少个由众多条线段组成的网格。

   3、使用pathfinding库进行2D寻路

   3、使用pathfinding库进行2D寻路

⑤ 、删除网格

  pathfindingjs是一个开源2D寻路库,能够在

  pathfindingjs是贰个开源2D寻路库,能够在

代码如下:

  pathfinding的基本用法如下:

  pathfinding的为主用法如下:

 1 function DeleteMeshes(arr)//假设一个数组里的都是mesh,彻底清空它
 2     {
 3         var len=arr.length;
 4         for(var i=0;i<len;i++)
 5         {
 6             if(arr[i].dispose)
 7                 arr[i].dispose();
 8         }
 9         arr=[];
10     }
 1 var finder = new PF.AStarFinder({//“寻路器”
 2     diagonalMovement: 3
 3 });
 4 
 5 。
 6 this.grid=new PF.Grid(this.len_x,this.len_y,this.walkabilityMatrix);//生成寻路网格 7 。


 8 
 9 function FindWaytogo(pickResult)//pickResult是Babylonjs中定义的“鼠标选取结果”对象
10 {
11     var faceId=pickResult.faceId;//点击了网格中的第几个面
12     var pickedMesh=pickResult.pickedMesh;//被点击的网格
13     var px=MyGame.player.mesh.position.x;//被控对象在场景中的水平位置
14     var py=MyGame.player.mesh.position.z;
15 
16     var len_x=MyGame.arena.len_x;//寻路网格的格数和每格的长度
17     var len_y=MyGame.arena.len_y;
18     var len_s=MyGame.arena.len_s;
19     if(px>-len_x*len_s/2&&px<len_x*len_s/2&&py>-len_y*len_s/2&&py<len_y*len_s/2&&MyGame.arena.grid)//如果使用了pathfinder的障碍矩阵
20     {
21         var arr_matrix=MyGame.arena.walkabilityMatrix;//寻路矩阵
22         var count=parseInt(faceId/2);//第几个方格
23         //接下来要把网格的面转换为寻路方格的坐标,后面还要把寻路方格的坐标转换为scene中的位置
24         //面数转换为方格坐标
25         var count_y=parseInt(count/len_x);
26         var count_x=count%len_x;
27         //场景坐标转化为方格坐标
28         var count_x0=parseInt(px/len_s+len_x/2);
29         var count_y0=parseInt(-py/len_s+len_y/2);
30 
31         //寻路,返回一个由方格坐标组成的数组
32         var path = finder.findPath(count_x0,count_y0 , count_x,count_y, MyGame.arena.grid.clone());//这些是寻路网格坐标
33         var len=path.length;
34         for(var i=0;i<len;i++)
35         {//把方格坐标转化为场景坐标
36             var obj=path[i];
37             obj[0]=(obj[0]-len_x/2)*len_s;
38             obj[1]=(-obj[1]+len_y/2)*len_s;
39         }
40 
41         path.push([pickResult.pickedPoint.x,pickResult.pickedPoint.z]);
42         MyGame.player.path_goto=path;//在使用时在生成高度
43         MyGame.player.positiontogo=[pickResult.pickedPoint.x,pickResult.pickedPoint.z];
44         path.shift();//把第一个出发节点去掉
45         console.log("生成路径,起点:["+px+","+py+"],终点:["+pickResult.pickedPoint.x+","+pickResult.pickedPoint.z+"]");
46     }
47 }
 1 var finder = new PF.AStarFinder({//“寻路器”
 2     diagonalMovement: 3
 3 });
 4 
 5 。
 6 this.grid=new PF.Grid(this.len_x,this.len_y,this.walkabilityMatrix);//生成寻路网格 7 。


 8 
 9 function FindWaytogo(pickResult)//pickResult是Babylonjs中定义的“鼠标选取结果”对象
10 {
11     var faceId=pickResult.faceId;//点击了网格中的第几个面
12     var pickedMesh=pickResult.pickedMesh;//被点击的网格
13     var px=MyGame.player.mesh.position.x;//被控对象在场景中的水平位置
14     var py=MyGame.player.mesh.position.z;
15 
16     var len_x=MyGame.arena.len_x;//寻路网格的格数和每格的长度
17     var len_y=MyGame.arena.len_y;
18     var len_s=MyGame.arena.len_s;
19     if(px>-len_x*len_s/2&&px<len_x*len_s/2&&py>-len_y*len_s/2&&py<len_y*len_s/2&&MyGame.arena.grid)//如果使用了pathfinder的障碍矩阵
20     {
21         var arr_matrix=MyGame.arena.walkabilityMatrix;//寻路矩阵
22         var count=parseInt(faceId/2);//第几个方格
23         //接下来要把网格的面转换为寻路方格的坐标,后面还要把寻路方格的坐标转换为scene中的位置
24         //面数转换为方格坐标
25         var count_y=parseInt(count/len_x);
26         var count_x=count%len_x;
27         //场景坐标转化为方格坐标
28         var count_x0=parseInt(px/len_s+len_x/2);
29         var count_y0=parseInt(-py/len_s+len_y/2);
30 
31         //寻路,返回一个由方格坐标组成的数组
32         var path = finder.findPath(count_x0,count_y0 , count_x,count_y, MyGame.arena.grid.clone());//这些是寻路网格坐标
33         var len=path.length;
34         for(var i=0;i<len;i++)
35         {//把方格坐标转化为场景坐标
36             var obj=path[i];
37             obj[0]=(obj[0]-len_x/2)*len_s;
38             obj[1]=(-obj[1]+len_y/2)*len_s;
39         }
40 
41         path.push([pickResult.pickedPoint.x,pickResult.pickedPoint.z]);
42         MyGame.player.path_goto=path;//在使用时在生成高度
43         MyGame.player.positiontogo=[pickResult.pickedPoint.x,pickResult.pickedPoint.z];
44         path.shift();//把第一个出发节点去掉
45         console.log("生成路径,起点:["+px+","+py+"],终点:["+pickResult.pickedPoint.x+","+pickResult.pickedPoint.z+"]");
46     }
47 }

值得注意的是,直接在控制台里实施mesh.dispose()并不奏效。

  那样,大家就把场景中的地方对应成了寻路网格中的地点,然后选择pathfinding生成了2D门路。要求留意的是pathfinding中的grid对象只可以使用1遍,再度寻路时必要重新生成grid或许应用grid的克隆对象。

  那样,大家就把场景中的地方对应成了寻路网格中的地方,然后采用pathfinding生成了2D路子。供给留意的是pathfinding中的grid对象只可以选用一回,再度寻路时索要重新生成grid也许使用grid的仿制对象。

此间也反映出CreateLineSystem的便利之处——删除法线时只要求dispose四个对象。

 

 

六 、鼠标移入时展现三角形音讯

  肆 、基于cannon.js物理引擎沿路径移动 

  肆 、基于cannon.js物理引擎沿路径移动 

鼠标动作监听代码:

  接下去必要让被控物体沿着钦点的路子运动,为了能让实体在坎坷不平的地形中活动时保持紧贴地面,作者在那边运用了cannonjs物理引擎(关于物理引擎的用法能够参考上一篇小说)。经过考试,那一个版本的cannonjs的单个物理仿真器最多帮衬对一千0个终端的大体仿真,所以前文无法把本地网格分成越来越多段。

  接下去必要让被控物体沿着钦命的门路运动,为了能让实体在坑坑洼洼的山势中活动时保持紧贴地面,作者在此处运用了cannonjs物理引擎(关于物理引擎的用法能够参照上一篇文章)。经过试验,那么些版本的cannonjs的单个物理仿真器最多帮助对一千0个极点的情理仿真,所以前文无法把当地网格分成更加多段。

 1 mesh_origin=new BABYLON.Mesh("mesh_origin",scene);//建立一个空的初始网格对象
 2         mesh_surface=new BABYLON.Mesh("mesh_surface",scene);
 3         mesh_surface0=new BABYLON.Mesh("mesh_surface0",scene);
 4         if(true)
 5         {//初始化三个GUI标签
 6             label_index1=new BABYLON.GUI.TextBlock();
 7             label_index1.text = "label_index1";
 8             label_index1.color="white";
 9             label_index1.isVisible=false;//初始化时标签不可见
10             //label_index1.linkWithMesh(mesh_surface0);//TextBlock并不是顶层元素
11             advancedTexture.addControl(label_index1);
12             label_index2=new BABYLON.GUI.TextBlock();
13             label_index2.text = "label_index2";
14             label_index2.color="white";
15             label_index2.isVisible=false;
16             //label_index2.linkWithMesh(mesh_surface0);
17             advancedTexture.addControl(label_index2);
18             label_index3=new BABYLON.GUI.TextBlock();
19             label_index3.text = "label_index3";
20             label_index3.color="white";
21             label_index3.isVisible=false;
22             //label_index3.linkWithMesh(mesh_surface0);
23             advancedTexture.addControl(label_index3);
24         }
25 //监听鼠标移动
26 canvas.addEventListener("mousemove", function(evt){
27 var pickInfo = scene.pick(scene.pointerX, scene.pointerY,null,null,camera0);//如果同时有多个激活的相机,则要明确的指出使用哪个相机
28             //cancelPropagation(evt);
29             //cancelEvent(evt);
30             label_index1.isVisible=false;
31             label_index2.isVisible=false;
32             label_index3.isVisible=false;
33             if(mesh_surface.dispose)
34             {
35                 mesh_surface.dispose();
36             }
37             if(mesh_surface0.dispose)
38             {
39                 mesh_surface0.dispose();
40             }
41             if(pickInfo.hit&&(pickInfo.pickedMesh.name=="mesh_origin"||pickInfo.pickedMesh.name=="mesh_ribbon"))//找到鼠标所在的三角形并重绘之
42             {
43           //在鼠标所指的地方绘制一个三角形,表示被选中的三角形
44                 var faceId=pickInfo.faceId;
45                 var pickedMesh=pickInfo.pickedMesh;
46                 var indices=[pickedMesh.geometry._indices[faceId*3]
47                     ,pickedMesh.geometry._indices[faceId*3+1],pickedMesh.geometry._indices[faceId*3+2]];
48                 var vb=pickedMesh.geometry._vertexBuffers;
49                 var position=vb.position._buffer._data;
50                 var normal=vb.normal._buffer._data;
51                 var uv=vb.uv._buffer._data;
52                 var len=arr_path[0].length;
53                 var p1={index:indices[0],position:[position[indices[0]*3],position[indices[0]*3+1],position[indices[0]*3+2]]
54                     ,normal:[normal[indices[0]*3],normal[indices[0]*3+1],normal[indices[0]*3+2]]
55                     ,uv:[uv[indices[0]*2],uv[indices[0]*2+1]],ppi:("1:"+(Math.round(indices[0]/len)+0))+"-"+(indices[0]%len)};//pathpointindex
56                 var p2={index:indices[1],position:[position[indices[1]*3],position[indices[1]*3+1],position[indices[1]*3+2]]
57                     ,normal:[normal[indices[1]*3],normal[indices[1]*3+1],normal[indices[1]*3+2]]
58                     ,uv:[uv[indices[1]*2],uv[indices[1]*2+1]],ppi:("2:"+(Math.round(indices[1]/len)+0))+"-"+(indices[1]%len)};
59                 var p3={index:indices[2],position:[position[indices[2]*3],position[indices[2]*3+1],position[indices[2]*3+2]]
60                     ,normal:[normal[indices[2]*3],normal[indices[2]*3+1],normal[indices[2]*3+2]]
61                     ,uv:[uv[indices[2]*2],uv[indices[2]*2+1]],ppi:("3:"+(Math.round(indices[2]/len)+0))+"-"+(indices[2]%len)};
62                 var po=[(p1.position[0]+p2.position[0]+p3.position[0])/3,(p1.position[1]+p2.position[1]+p3.position[1])/3,(p1.position[2]+p2.position[2]+p3.position[2])/3];
63                 var numm=2;
64                 mesh_surface0=newland.make_tryangle(p1,p2,p3,"mesh_surface1",scene);//使用三个点绘制一个三角形
65                 mesh_surface0.material=mat_green;
66                 mesh_surface0.sideOrientation==BABYLON.Mesh.DOUBLESIDE;
67                 mesh_surface0.layerMask=2;
68                 label_index1.isVisible=true;
69                 //label_index1.layerMask=2;//这个属性对于gui被管对象并不生效?
70                 label_index1.text=p1.ppi;//ppi表示这个顶点是三角形的第几个顶点,以及这个顶点位于第几条路径的第几个位置
71                 var pos1=new BABYLON.Vector3(p1.position[0],p1.position[1],p1.position[2]);
72                 label_index1.moveToVector3(pos1,scene);
73                 label_index1.itspos=pos1;
74                 label_index2.isVisible=true;
75                 label_index2.text=p2.ppi;
76                 var pos2=new BABYLON.Vector3(p2.position[0],p2.position[1],p2.position[2]);
77                 label_index2.moveToVector3(pos2,scene);
78                 label_index2.itspos=pos2;
79                 label_index3.isVisible=true;
80                 label_index3.text=p3.ppi;
81                 var pos3=new BABYLON.Vector3(p3.position[0],p3.position[1],p3.position[2]);
82                 label_index3.moveToVector3(pos3,scene);
83                 label_index3.itspos=pos3;
84                 //将三个点移动到场景的中心
85                 pt=[(p1.position[0]-po[0])*numm,(p1.position[1]-po[1])*numm,(p1.position[2]-po[2])*numm];
86                 p1.position=pt;
87                 pt=[(p2.position[0]-po[0])*numm,(p2.position[1]-po[1])*numm,(p2.position[2]-po[2])*numm];
88                 p2.position=pt;
89                 pt=[(p3.position[0]-po[0])*numm,(p3.position[1]-po[1])*numm,(p3.position[2]-po[2])*numm];
90                 p3.position=pt;
91           //在场景的中心再绘制一个大一倍的三角形
92                 mesh_surface=newland.make_tryangle(p1,p2,p3,"mesh_surface",scene);
93                 mesh_surface.material=mat_green;
94                 mesh_surface.sideOrientation==BABYLON.Mesh.DOUBLESIDE;
95                 mesh_surface.layerMask=1;//遮罩层次是1
96 
97             }
98 
99         },false);

  大家在那一个场所中监听“右键点击地面”的轩然大波,代码如下:

  大家在这么些意况中监听“右键点击地面”的事件,代码如下:

内需注意的有以下几点:

 1 canvas.addEventListener("click", function(evt) {
 2             var width = engine.getRenderWidth();
 3             var height = engine.getRenderHeight();
 4             var pickInfo = scene.pick(width/2, height/2, null, false, _this.camera);//点击信息
 5             if(evt.button==2)//右键单击
 6             {
 7                 cancelEvent(evt);//阻止默认响应
 8                 if(pickInfo.hit&&pickInfo.pickedMesh.name=="mesh_ground")//点击到了地面上
 9                 {
10                     MyGame.player.mesh.physicsImpostor.setMass(70);//给被控物体赋予质量,这样它才可以下落
11                     FindWaytogo(pickInfo);//在玩家到点击目的地之间找到一条路径
12                     var mesh_togo=BABYLON.Mesh.CreateBox("box", 1, scene);//目标方块
13                     mesh_togo.position = pickInfo.pickedPoint.clone();//pickResult.pickedPoint
14                     mesh_togo.renderingGroupId=2;
15                     MyGame.player.mesh_togo=mesh_togo;
16                 }
17             }
18 
19 
20 
21         }, false);
 1 canvas.addEventListener("click", function(evt) {
 2             var width = engine.getRenderWidth();
 3             var height = engine.getRenderHeight();
 4             var pickInfo = scene.pick(width/2, height/2, null, false, _this.camera);//点击信息
 5             if(evt.button==2)//右键单击
 6             {
 7                 cancelEvent(evt);//阻止默认响应
 8                 if(pickInfo.hit&&pickInfo.pickedMesh.name=="mesh_ground")//点击到了地面上
 9                 {
10                     MyGame.player.mesh.physicsImpostor.setMass(70);//给被控物体赋予质量,这样它才可以下落
11                     FindWaytogo(pickInfo);//在玩家到点击目的地之间找到一条路径
12                     var mesh_togo=BABYLON.Mesh.CreateBox("box", 1, scene);//目标方块
13                     mesh_togo.position = pickInfo.pickedPoint.clone();//pickResult.pickedPoint
14                     mesh_togo.renderingGroupId=2;
15                     MyGame.player.mesh_togo=mesh_togo;
16                 }
17             }
18 
19 
20 
21         }, false);

a、鼠标指向时展现的是以此点在arr_path中的索引,而不是在“顶点数据对象”中的索引!

  然后在每回渲染从前实施以下运动格局:

  然后在历次渲染从前实施以下运动形式:

b、最初的计划是像魔兽争霸3一样在窗口的左下角建立一个遮罩层次为1的小视口,用来特写被选中的三角(mesh_三星平板),然而后来发觉Babylon.js的GUI不能够设置遮罩层次,也无法像鼠标采用一样设置相对于哪3个相机,所以废除了左下角的小视口。

 1         scene.registerBeforeRender(function() {
 2             if(MyGame.flag_startr==1)//如果开始渲染了
 3             {
 4                 if(MyGame.flag_view=="first"||MyGame.flag_view=="third")
 5                 {
 6                     physics20170725(MyGame.player);
 7                 }
 8                 if(MyGame.flag_view=="free")
 9                 {
10                     pathgoto20170808(MyGame.player);
11                 }
12             }
13         });
 1         scene.registerBeforeRender(function() {
 2             if(MyGame.flag_startr==1)//如果开始渲染了
 3             {
 4                 if(MyGame.flag_view=="first"||MyGame.flag_view=="third")
 5                 {
 6                     physics20170725(MyGame.player);
 7                 }
 8                 if(MyGame.flag_view=="free")
 9                 {
10                     pathgoto20170808(MyGame.player);
11                 }
12             }
13         });

借使须要加上海广播台口,代码如下:

 

 

 1 var mm = new BABYLON.FreeCamera("minimap", new BABYLON.Vector3(0,0,-20), scene);
 2         mm.layerMask = 1;
 3         var xstart = 0.0,
 4                 ystart = 0.1;//意为占屏幕宽高的比例
 5         var width = 0.2,
 6                 height = 0.2;
 7         //视口边界从左下角开始
 8         mm.viewport = new BABYLON.Viewport(
 9                 xstart,
10                 ystart,
11                 width,
12                 height
13         );
14         scene.activeCameras.push(mm);
 1 function pathgoto20170808(obj)//obj是player
 2 {
 3     if(true)
 4     //if(obj.standonTheGround==1)//站在地面上时考虑将质量设为0?
 5     {
 6         if(obj.path_goto!="sleep"&&obj.path_goto!="lose")
 7         {
 8             var len_x=MyGame.arena.len_x;
 9             var len_y=MyGame.arena.len_y;
10             var len_s=MyGame.arena.len_s;
11             var vl_now=obj.mesh.physicsImpostor.getLinearVelocity();
12 
13             if(obj.path_goto.length>0)
14             {
15                 var px=obj.mesh.position.x;//全是场景坐标!!
16                 var py=obj.mesh.position.z;
17                 var count_x0=px;
18                 var count_y0=py;
19                 var count_x=obj.path_goto[0][0];
20                 var count_y=obj.path_goto[0][1];
21                 var len=obj.path_goto.length;
22                 var count_x2=obj.path_goto[len-1][0];
23                 var count_y2=obj.path_goto[len-1][1];
24                 var y_obj=obj.mesh.position.y;
25                 if((Math.pow(count_x0-count_x2,2)+Math.pow(count_y0-count_y2,2))<0.25*len_s*len_s)
26                 {//在移动过程中因未知原因跳到距终点0.5以内距离的地方,直接寻找最终点
27                     console.log("在最终格内");
28                     if((Math.pow(count_x0-count_x2,2)+Math.pow(count_y0-count_y2,2))<0.01*len_s*len_s)//到达0.1距离以内的地方,认为到达最终目标,直接定位
29                     {
30 
31                         obj.mesh.position.x=count_x;
32                         obj.mesh.position.z=count_y;
33                         obj.path_goto="sleep";
34                         console.log("到达最终目标:["+obj.mesh.position.x+","+obj.mesh.position.y+","+obj.mesh.position.z+"]");
35                         obj.mesh.physicsImpostor.setMass(0);//质量设为零将不会下落
36                         obj.mesh_togo.dispose();
37                         obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
38                         obj.mesh.physicsImpostor.setLinearVelocity(new BABYLON.Vector3(0,0,0));
39                         
40                     }
41                     else{
42                         var v_temp=new BABYLON.Vector3(count_x2,0,count_y2).subtract(new BABYLON.Vector3(obj.mesh.position.x,0,obj.mesh.position.z)).normalize().scaleInPlace(obj.vm.forward);
43                         v_temp.y=vl_now.y<=0?vl_now.y:0;//这个单位应该脚踏实地的平稳运动
44                         obj.mesh.physicsImpostor.setLinearVelocity(v_temp);
45                         //obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
46                         if(obj.path_goto.length>1)
47                         {
48                             obj.path_goto=[obj.path_goto[len-1]];//只剩一个最终目标
49                         }
50                     }
51                 }
52                 else if((Math.pow(count_x0-count_x,2)+Math.pow(count_y0-count_y,2))>4*len_s*len_s)
53                 {//在移动过程中因未知原因跳到距下个目标格2以外距离的地方,需要重新寻路,这种计算可能耗时较大,不能每帧执行!!
54                     obj.path_goto="lose";
55                     //obj.mesh.physicsImpostor.setMass(0);//不掉落
56                     obj.mesh.physicsImpostor.setLinearVelocity(new BABYLON.Vector3(0,0,0));
57                     obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
58                     return false;
59                 }
60                 else if(obj.path_goto.length>1&&(Math.pow(count_x0-count_x,2)+Math.pow(count_y0-count_y,2))<0.25*len_s*len_s)
61                 {//距离下一寻路格足够近,切换下一寻路格
62 
63                     obj.path_goto.shift();
64                     count_x=obj.path_goto[0][0];
65                     count_y=obj.path_goto[0][1];
66                     console.log("切换下一个寻路单元格:["+count_x+","+count_y+"]");
67                     var v_temp=new BABYLON.Vector3(count_x,0,count_y).subtract(new BABYLON.Vector3(obj.mesh.position.x,0,obj.mesh.position.z)).normalize().scaleInPlace(obj.vm.forward);
68                     v_temp.y=vl_now.y<=0?vl_now.y:0;
69                     obj.mesh.physicsImpostor.setLinearVelocity(v_temp);
70                     //obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
71                 }
72                 else//正常向目标寻路格移动
73                 {
74                     console.log("普通寻路");
75                     var v_temp=new BABYLON.Vector3(count_x,0,count_y).subtract(new BABYLON.Vector3(obj.mesh.position.x,0,obj.mesh.position.z)).normalize().scaleInPlace(obj.vm.forward);
76                     v_temp.y=vl_now.y<=0?vl_now.y:0;
77                     obj.mesh.physicsImpostor.setLinearVelocity(v_temp);
78                     //obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
79                 }
80 
81             }
82         }
83         else
84         {
85             //obj.mesh.physicsImpostor.setMass(0);//不掉落
86         }
87     }
88 
89 
90 
91 }
 1 function pathgoto20170808(obj)//obj是player
 2 {
 3     if(true)
 4     //if(obj.standonTheGround==1)//站在地面上时考虑将质量设为0?
 5     {
 6         if(obj.path_goto!="sleep"&&obj.path_goto!="lose")
 7         {
 8             var len_x=MyGame.arena.len_x;
 9             var len_y=MyGame.arena.len_y;
10             var len_s=MyGame.arena.len_s;
11             var vl_now=obj.mesh.physicsImpostor.getLinearVelocity();
12 
13             if(obj.path_goto.length>0)
14             {
15                 var px=obj.mesh.position.x;//全是场景坐标!!
16                 var py=obj.mesh.position.z;
17                 var count_x0=px;
18                 var count_y0=py;
19                 var count_x=obj.path_goto[0][0];
20                 var count_y=obj.path_goto[0][1];
21                 var len=obj.path_goto.length;
22                 var count_x2=obj.path_goto[len-1][0];
23                 var count_y2=obj.path_goto[len-1][1];
24                 var y_obj=obj.mesh.position.y;
25                 if((Math.pow(count_x0-count_x2,2)+Math.pow(count_y0-count_y2,2))<0.25*len_s*len_s)
26                 {//在移动过程中因未知原因跳到距终点0.5以内距离的地方,直接寻找最终点
27                     console.log("在最终格内");
28                     if((Math.pow(count_x0-count_x2,2)+Math.pow(count_y0-count_y2,2))<0.01*len_s*len_s)//到达0.1距离以内的地方,认为到达最终目标,直接定位
29                     {
30 
31                         obj.mesh.position.x=count_x;
32                         obj.mesh.position.z=count_y;
33                         obj.path_goto="sleep";
34                         console.log("到达最终目标:["+obj.mesh.position.x+","+obj.mesh.position.y+","+obj.mesh.position.z+"]");
35                         obj.mesh.physicsImpostor.setMass(0);//质量设为零将不会下落
36                         obj.mesh_togo.dispose();
37                         obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
38                         obj.mesh.physicsImpostor.setLinearVelocity(new BABYLON.Vector3(0,0,0));
39                         
40                     }
41                     else{
42                         var v_temp=new BABYLON.Vector3(count_x2,0,count_y2).subtract(new BABYLON.Vector3(obj.mesh.position.x,0,obj.mesh.position.z)).normalize().scaleInPlace(obj.vm.forward);
43                         v_temp.y=vl_now.y<=0?vl_now.y:0;//这个单位应该脚踏实地的平稳运动
44                         obj.mesh.physicsImpostor.setLinearVelocity(v_temp);
45                         //obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
46                         if(obj.path_goto.length>1)
47                         {
48                             obj.path_goto=[obj.path_goto[len-1]];//只剩一个最终目标
49                         }
50                     }
51                 }
52                 else if((Math.pow(count_x0-count_x,2)+Math.pow(count_y0-count_y,2))>4*len_s*len_s)
53                 {//在移动过程中因未知原因跳到距下个目标格2以外距离的地方,需要重新寻路,这种计算可能耗时较大,不能每帧执行!!
54                     obj.path_goto="lose";
55                     //obj.mesh.physicsImpostor.setMass(0);//不掉落
56                     obj.mesh.physicsImpostor.setLinearVelocity(new BABYLON.Vector3(0,0,0));
57                     obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
58                     return false;
59                 }
60                 else if(obj.path_goto.length>1&&(Math.pow(count_x0-count_x,2)+Math.pow(count_y0-count_y,2))<0.25*len_s*len_s)
61                 {//距离下一寻路格足够近,切换下一寻路格
62 
63                     obj.path_goto.shift();
64                     count_x=obj.path_goto[0][0];
65                     count_y=obj.path_goto[0][1];
66                     console.log("切换下一个寻路单元格:["+count_x+","+count_y+"]");
67                     var v_temp=new BABYLON.Vector3(count_x,0,count_y).subtract(new BABYLON.Vector3(obj.mesh.position.x,0,obj.mesh.position.z)).normalize().scaleInPlace(obj.vm.forward);
68                     v_temp.y=vl_now.y<=0?vl_now.y:0;
69                     obj.mesh.physicsImpostor.setLinearVelocity(v_temp);
70                     //obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
71                 }
72                 else//正常向目标寻路格移动
73                 {
74                     console.log("普通寻路");
75                     var v_temp=new BABYLON.Vector3(count_x,0,count_y).subtract(new BABYLON.Vector3(obj.mesh.position.x,0,obj.mesh.position.z)).normalize().scaleInPlace(obj.vm.forward);
76                     v_temp.y=vl_now.y<=0?vl_now.y:0;
77                     obj.mesh.physicsImpostor.setLinearVelocity(v_temp);
78                     //obj.mesh.physicsImpostor.setAngularVelocity(new BABYLON.Vector3(0,0,0));//停下
79                 }
80 
81             }
82         }
83         else
84         {
85             //obj.mesh.physicsImpostor.setMass(0);//不掉落
86         }
87     }
88 
89 
90 
91 }

c、须要注意的是GUI是二次性绘制在视口上的,私下认可景况下正是相关的网格位置发生变化,GUI依然会保持在视口上最初的岗位。linkWithMesh方法能够将GUI和网格绑定起来,可是就像只好对部分“底层的”GUI类型生效,为了使得标签跟随顶点移动,要求手动在每一帧渲染在此之前更新标签的岗位:

  那里分两种也许发生的移位情形(最广大的二种)分别安装被控物体的线速度,使得物体平稳的沿着路径运动,当物体到达目的时将进入sleep状态,当物体偏离路径时将跻身lose状态,程序每分钟检查一下物体是不是lose,假使lose则重复寻路(没有测试过):

  那里分两种或然发生的移动景况(最广大的两种)分别设置被控物体的线速度,使得物体平稳的沿着路径运动,当物体到达指标时将跻身sleep状态,当物体偏离路径时将进入lose状态,程序每分钟检查一下物体是否lose,若是lose则再一次寻路(没有测试过):

 1 scene.registerBeforeRender(function() {
 2             if(scene.isReady())
 3             {
 4                 if(label_index1.isVisible==true)//不断刷新gui的位置
 5                 {//在具有多个激活相机时选择了错误的参考相机?-》会强制选择最新建立的相机
 6                     label_index1.moveToVector3(label_index1.itspos,scene);
 7                     label_index2.moveToVector3(label_index2.itspos,scene);
 8                     label_index3.moveToVector3(label_index3.itspos,scene);
 9                 }
10             }
11         });
 1 _this.currentframet=new Date().getTime();
 2                 _this.DeltaTime=_this.currentframet-_this.lastframet;//取得两帧之间的时间
 3                 _this.lastframet=_this.currentframet;
 4                 _this.nohurry+=_this.DeltaTime;
 5                 if(MyGame&&_this.nohurry>1000)//每一秒进行一次导航修正
 6                 {
 7                     _this.nohurry=0;
 8                     if(_this.player.path_goto=="lose")//发现迷失了路途
 9                     {
10                         console.log("发现迷路,重新规划路径");
11                         var len_x=MyGame.arena.len_x;
12                         var len_y=MyGame.arena.len_y;
13                         var len_s=MyGame.arena.len_s;
14                         //场景坐标转化为方格坐标
15                         var count_x0=parseInt(_this.player.mesh.position.x/len_s+len_x/2);
16                         var count_y0=parseInt(-_this.player.mesh.position.z/len_s+len_y/2);
17                         var count_x=parseInt(_this.player.positiontogo[0]/len_s+len_x/2);
18                         var count_y=parseInt(-_this.player.positiontogo[1]/len_s+len_y/2);
19                         var path = finder.findPath(count_x0,count_y0 , count_x,count_y, MyGame.arena.grid.clone());//这些是寻路网格坐标
20                         var len=path.length;
21                         for(var i=0;i<len;i++)
22                         {//把方格坐标转化为场景坐标
23                             var obj=path[i];
24                             obj[0]=(obj[0]-len_x/2)*len_s;
25                             obj[1]=(-obj[1]+len_y/2)*len_s;
26                         }
27                         path.push(MyGame.player.positiontogo);
28                         path.shift();//把第一个出发节点去掉
29                         MyGame.player.path_goto=path;//在使用时在生成高度
30                         console.log("生成路径,起点:["+_this.player.mesh.position.x+","+_this.player.mesh.position.z+"]" +
31                             ",终点:["+_this.player.positiontogo[0]+","+_this.player.positiontogo[1]+"]");
32                     }
33                 }
 1 _this.currentframet=new Date().getTime();
 2                 _this.DeltaTime=_this.currentframet-_this.lastframet;//取得两帧之间的时间
 3                 _this.lastframet=_this.currentframet;
 4                 _this.nohurry+=_this.DeltaTime;
 5                 if(MyGame&&_this.nohurry>1000)//每一秒进行一次导航修正
 6                 {
 7                     _this.nohurry=0;
 8                     if(_this.player.path_goto=="lose")//发现迷失了路途
 9                     {
10                         console.log("发现迷路,重新规划路径");
11                         var len_x=MyGame.arena.len_x;
12                         var len_y=MyGame.arena.len_y;
13                         var len_s=MyGame.arena.len_s;
14                         //场景坐标转化为方格坐标
15                         var count_x0=parseInt(_this.player.mesh.position.x/len_s+len_x/2);
16                         var count_y0=parseInt(-_this.player.mesh.position.z/len_s+len_y/2);
17                         var count_x=parseInt(_this.player.positiontogo[0]/len_s+len_x/2);
18                         var count_y=parseInt(-_this.player.positiontogo[1]/len_s+len_y/2);
19                         var path = finder.findPath(count_x0,count_y0 , count_x,count_y, MyGame.arena.grid.clone());//这些是寻路网格坐标
20                         var len=path.length;
21                         for(var i=0;i<len;i++)
22                         {//把方格坐标转化为场景坐标
23                             var obj=path[i];
24                             obj[0]=(obj[0]-len_x/2)*len_s;
25                             obj[1]=(-obj[1]+len_y/2)*len_s;
26                         }
27                         path.push(MyGame.player.positiontogo);
28                         path.shift();//把第一个出发节点去掉
29                         MyGame.player.path_goto=path;//在使用时在生成高度
30                         console.log("生成路径,起点:["+_this.player.mesh.position.x+","+_this.player.mesh.position.z+"]" +
31                             ",终点:["+_this.player.positiontogo[0]+","+_this.player.positiontogo[1]+"]");
32                     }
33                 }

七 、接纳顶点:

 

 

3Ds马克斯和Blender(Babylon.js库在3D模型部分参考了Blender的诸多设计)都选拔鼠标在网格中选拔需求修改的区域,笔者不是很习惯那种方法,所以考虑用JS函数代替鼠标操作:

  那样,大家就成功的完毕了在WebGL场景中寻路的对象,接下去能够品味修改pathfinding使之能依照不一样地貌开始展览加权寻路,以及控制五个单位进行寻路行为。

  那样,大家就打响的做到了在WebGL场景中寻路的靶子,接下去能够品尝修改pathfinding使之能依据不一致地貌开始展览加权寻路,以及控制四个单位开展寻路行为。

 1 var lines_inpicked={};//线段系统对象,表示所有被选中点影响的线段
 2     var arr_ij=[];//记录被选中的点在arr_path中的索引的数组
 3     /*DeleteMeshes([lines_inpicked]);
 4     * PickPoints([[0,0],[0,12],[1,1]],mesh_origin)
 5     * */
 6     //选定一些顶点
 7     function PickPoints(arr,mesh)
 8     {
 9         if(arr_path.length==0)
10         {
11             alert("尚未生成路径数组!");
12             return;
13         }
14         if(lines_inpicked.dispose)
15         {
16             lines_inpicked.dispose();
17         }
18         //arr_ij=[];
19         //为了后面考虑,需要先对arr整体遍历一遍,把首尾接口处关联起来
20         arr_ij=arr;//把路径和点的位置记录下来
21         var vb=mesh.geometry._vertexBuffers;
22         var data_pos=vb.position._buffer._data;
23         var len_pos=data_pos.length;
24         var data_index=mesh.geometry._indices;
25         var len_index=data_index.length;
26         var len=arr.length;
27         var lines=[];
28         for(var i=0;i<len;i++)//对于每一个需要显示的被选择点
29         {
30             var int0=arr[i][0];
31             var int1=arr[i][1];
32             var vec=arr_path[int0][int1];//获取到路径数组中的一个Vector3对象
33             //假设路径数组和顶点数据是一一对应的?同时假设每一条路径的长度都和第一条相同
34             var arr_index=[int0*arr_path[0].length+int1];//所有位于所选位置的顶点在顶点数据对象中的索引
35             //下面遍历网格的绘制索引,找出这个被选中的顶点每一次的使用情况
36             for(var j=0;j<len_index;j+=3)//根据顶点在三角形中的位置分三种情况讨论
37             {//绘制出和这个顶点相关的所有线段,这样绘制会有很严重的线段重合!观察是否对性能有很大的影响
38                 var len2=arr_index.length;
39                 for(var k=0;k<len2;k++)
40                 {
41                     if(arr_index[k]==data_index[j])//三角形的第一个顶点
42                     {//把这个顶点和三角形中的另两个顶点用黄线连起来
43                         var num2=data_index[j+1]*3;
44                         var num3=data_index[j+2]*3;
45                         var vec2=new BABYLON.Vector3(data_pos[num2],data_pos[num2+1],data_pos[num2+2]);
46                         var vec3=new BABYLON.Vector3(data_pos[num3],data_pos[num3+1],data_pos[num3+2]);
47                         lines.push([vec,vec2]);
48                         lines.push([vec,vec3]);
49                     }
50                     else if(arr_index[k]==data_index[j+1])//三角形的第一个顶点
51                     {
52                         var num2=data_index[j]*3;
53                         var num3=data_index[j+2]*3;
54                         var vec2=new BABYLON.Vector3(data_pos[num2],data_pos[num2+1],data_pos[num2+2]);
55                         var vec3=new BABYLON.Vector3(data_pos[num3],data_pos[num3+1],data_pos[num3+2]);
56                         lines.push([vec,vec2]);
57                         lines.push([vec,vec3]);
58                     }
59                     else if(arr_index[k]==data_index[j+2])//三角形的第一个顶点
60                     {
61                         var num2=data_index[j]*3;
62                         var num3=data_index[j+1]*3;
63                         var vec2=new BABYLON.Vector3(data_pos[num2],data_pos[num2+1],data_pos[num2+2]);
64                         var vec3=new BABYLON.Vector3(data_pos[num3],data_pos[num3+1],data_pos[num3+2]);
65                         lines.push([vec,vec2]);
66                         lines.push([vec,vec3]);
67                     }
68                 }
69             }
70         }
71         lines_inpicked=new BABYLON.MeshBuilder.CreateLineSystem("lines_normal",{lines:lines,updatable:false},scene);
72         lines_inpicked.color=new BABYLON.Color3(1, 1, 0);
73     }
74     //需要一些选择选定顶点的方法

  

  

有以下几处须求留意:

  

  

a、因为MakeRing生成的路径里包蕴三个重合的点(首尾),为了有限扶助变形后的网格仍旧两次三番,在增选时那多少个重合的点必须同时被入选,经过考虑,规定这些保障全进度重合点同时入选的操作在生成arr数组参数时开始展览。

b、因为基础网格mesh_origin的每二个极端恰好地点分裂,所以一初阶自笔者认为“与被入选的点的职位相同的点”应该有着与被选中式点心相同的变形效果,可是实际上经过网格变形后,完全只怕出现七个不相干的极端位于同一职分的意况,那时应用相同的变形效果会并发谬误,比如人能够把手放在腿上,那时手和腿的接触点具有同等的岗位,但假若就此对这三个点选取相同的变形效果,就很奇妙了。同时如前文所说,有时arr_path中贮存的地方和顶峰数据中贮存的岗位也许出现轻微的不是。

末尾动用的法子是将arr_path中的数组转化为终极数据对象中的数组。

c、那里一分区直接选举择了多少个点展开变形,还索要编写制定一些遵照某种规则批量挑选点的不二法门,也指望大家能帮小编想一想怎么着挑选顶点相比较便宜。

⑧ 、网格变形:

代码如下:

 1 /*
 2     * TransVertex(mesh_origin,arr_ij,BABYLON.Matrix.RotationX(Math.PI/2))
 3     *TransVertex(mesh_origin,arr_ij,BABYLON.Matrix.Translation(0.5,0,0))
 4     * */
 5     //移动选定的顶点,同时更新网格、选取线、法线
 6     function TransVertex(mesh,arr,matrix)
 7     {
 8         var len=arr.length;
 9         for(var i=0;i<len;i++)//移动路径数组里的每个顶点
10         {
11             //var vec=arr_path[arr[i][0]][arr[i][1]];
12             arr_path[arr[i][0]][arr[i][1]]=BABYLON.Vector3.TransformCoordinates(arr_path[arr[i][0]][arr[i][1]],matrix);
13         }
14         //更新网格,发现设置了closePath:true之后在顶点数据里还是会自动补上一个接续点,这还不如一开始自己添加!起码自己添加可以保证路径数组和顶点数据的一致性!!!!
15         mesh=BABYLON.MeshBuilder.CreateRibbon(mesh.name,{pathArray:arr_path,updatable:true,instance:mesh,closePath:false,closeArray:false});
16         //上面的更新重绘是默认重算法线方向的,这与直接修改顶点数据不同
17         //清空法线
18         DeleteMeshes([lines_normal]);
19         //更新选取顶点表示
20         PickPoints(arr,mesh);
21     }
22     //需要一些生成变化矩阵的方法

实则那里活动的极限和后面选用的点没有关联,不选择也得以一直变形,只可是不会有黄线显示罢了。那里也如出一辙须求部分变型更扑朔迷离的变换矩阵的形式。

9、导出:

导出方法的调用如下:

 1 /*ExportMesh("1",mat_blue)*/
 2     function ExportMesh(filename,mat)
 3     {
 4         try{
 5             newland.ExportBabylonMesh([mesh_origin],filename,mat);
 6         }
 7         catch(e)
 8         {
 9             console.error(e)
10         }
11     }

函数的首先个参数是导出后的文件名(不包涵扩展名),第三个参数是网格使用的质量对象(权且只帮忙简单的颜料质感)。

内部ExportBabylonMesh是自己编写的newland库中的一个艺术,那个办法在前边境海关与3D模型的稿子中也有提到过(

在导入模型文件时后者会报错:“attempt to access out of range vertices in
attribute
0”,那代表在导入模型时顶点数据数组没有科学的载入,笔者的解决方案是导出前将data属性强制转化为数组类型:

 1 //将TypedArray转化为普通array
 2 newland.BuffertoArray2=function(arr)
 3 {
 4     var arr2=[];
 5     var len=arr.length;
 6     for(var i=0;i<len;i++)
 7     {
 8         arr2.push(arr[i]);
 9     }
10     return arr2;
11 }

对于旧版的Babylon.js应该能够不加修改的采用那些情势,因为typedArray也具备数组的大部分作用。

10、导入:

在另四个页面里福寿齐天模型导入效率,那个页面同样在“基础场景”的底子上编写制定,个中程导弹入方法如下:

 1 function ImportMesh(objname,filepath,filename)
 2     {
 3 
 4         BABYLON.SceneLoader.ImportMesh(objname, filepath, filename, scene
 5                 , function (newMeshes, particleSystems, skeletons)
 6                 {//载入完成的回调函数
 7                     if(mesh_origin&&mesh_origin.dispose)
 8                     {
 9                         mesh_origin.dispose();
10                     }
11                     mesh_origin=newMeshes[0];
12                     //mesh_origin.material=mat_frame;
13                     //mesh_origin.layerMask=2;
14                 }
15         );
16     }

 

20180807修改

使用上述方法创立了三个“农夫山泉4L装塑料桶”的网格,能够经过

最后发生的网格如下图:

澳门葡京 27

实践申明,对于具有一定排布规律的多顶点网格来说,使用编制程序方法发生网格比较方便。

 

20180808修改

因而查看文书档案,发现固然高等动态纹理在确霎时无所适从钦点在哪些相机中举行展示,但她的属性匡助多相机设置,须要设置的质量是advancedTexture.layer.layerMask!

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website