Babylon.js引擎
Babylon.js是由HTML5和WebGL构建的3D游戏的完整javascript,与Three.js引擎不同,它倾向于基于Web进行游戏开发与碰撞检测 。
一、简介
Babylon.js支持WebGL 2.0的新特性包括多重渲染目标,顶点数组对象,一致缓冲区对象,遮挡查询和3D纹理等。
具体功能:
❑ 根据开发人员的需求可方便快捷地创建出3D图形。
❑ 为物体的渲染提供多种类型的纹理和材质。
❑ 自带强大的阴影计算功能,支持PCF和PCSS阴影算法。
❑ 对物理引擎进行封装,为Web游戏开发者提供了极大的便利。
❑ 支持多种格式的3D物体模型和骨骼动画,让3D场景更加丰富。
❑ 引擎中带有多种着色器,可以实现多种逼真的效果。
二、应用
此示例显示一个旋转球体,具体代码如下:
<! DOCTYPE html>2 <html>3 <head>4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />5 <title>Babylon.js sample code</title>6 <script type="text/javascript" src="bulid/babylon.custom.js"></script>7 <style>8 ......//此处省略CSS样式的定义,请读者自行查看随书源代码9 </style>10 </head>11 <body>12 <span id="fpsLabel">FPS</span>13 <span id="versionLabel">Version</span>14 <canvas id="renderCanvas"></canvas>15 <script>16 var canvas = document.getElementById("renderCanvas"); //获取Canvas对象17 var engine = new BABYLON.Engine(canvas, true); //获取Babylon引擎对象18 document.getElementById("versionLabel").innerHTML=19 ' Version <br>WebGL '+engine.webGLVersion; //获取引擎的WebGL版本20 var createScene = function () { //创建场景的方法21 var scene = new BABYLON.Scene(engine); //创建场景对象22 var camera = new BABYLON.ArcRotateCamera("camera1",23 0, 0, 0, new BABYLON.Vector3(0, 0, 0), scene); //创建弧度旋转摄像机24 camera.setPosition(new BABYLON.Vector3(0,40,40)); //设置摄像机的位置25 camera.attachControl(canvas, true); //添加对Canvas的控制26 var light = new BABYLON.DirectionalLight("DirectionalLight",27 new BABYLON.Vector3(-1, -1, -1), scene); //创建平行光28 light.position=new BABYLON.Vector3(30,30,30); //设置阴影投射的位置29 var materialSphere1=new BABYLON.StandardMaterial("materialSphere1", scene);30 materialSphere1.wireframe = true; //是否使用网格31 var sphere=BABYLON.MeshBuilder.CreateSphere("sphere", {diameter:30}, scene); //球体32 sphere.material=materialSphere1; //设置球体的材质33 var angle=0; //角度34 scene.onBeforeRenderObservable.add(()=>{ //渲染前的执行函数35 angle=angle+0.01; //增加角度36 sphere.rotation.set(0, angle,0); //修改球体的旋转角度37 })38 return scene; }; //返回场景对象39 var fpsLabel=document.getElementById('fpsLabel'); //获取FPS标签的DOM对象40 var scene=createScene(); //创建场景41 engine.runRenderLoop(function () { //启动渲染循环42 if (scene) { //如果场景创建完成43 fpsLabel.innerHTML=' FPS <br> ${Math.floor(engine.getFps())}';
44 scene.render(); //渲染场景
45 }});
46 window.addEventListener("resize", function () { //窗口变化监听
47 engine.resize(); //引擎重新设置窗口尺寸
48 });
49 </script>
50 </body>
51 </html>
❑ 第1~14行为网页开发中经常使用的一些标签。其功能为设置网页标题,显示页面的全屏效果,显示FPS和引擎使用的WebGL的版本以及将build目录下的babylon.custom.js作为外部文件引入案例中进行使用。
❑ 第16~19行的代码为获取Canvas的DOM对象、Babylon的引擎对象和当前Babylon.js使用的WebGL版本。根据浏览器对WebGL的支持度不同,此处获取到的版本会有所不用。
❑ 第20~38行的代码为创建场景。主要包括创建场景对象和摄像机并添加控制,创建光源、材质、球体并指定其材质,以及在渲染之前修改球体的旋转角度。这些都是Babylon.js开发中必不可少的部分,后文将详细介绍。
❑ 第39~51行代码的功能为获取FPS标签对象,创建场景,启动渲染循环以进行场景的渲染以及FPS的更新。最后添加窗口变化监听,当窗口大小发生变化时,引擎会重新设置渲染窗口的大小,保证渲染出的画面不会变形。
三 组件
(1)场景
它是其它组件的容器,有许多操作函数,下面简要介绍几种操作函数 。
getScene() 获取与场景关联的引擎
getMeshByName() :根据名字获取场景中的网格对象
removeMesh() :删除场景网格列表中的网格对象
registerBeforeRender() :在每帧渲染之前注册一个函数
(2)摄像机
与Three.js中正交、透视摄像机不同,此处摄像机更加专注于控制,主要有通用摄像机、弧度旋转相机、跟随相机等。
通用相机是其默认相机,它可以通过键盘和鼠标对其进行控制,在移动端可以通过手指触摸控制相机 ,示例如下:
1 var createScene = function () { //创建场景2 var scene = new BABYLON.Scene(engine); //获取场景对象3 //创建通用相机,并指定相机的名字和位置4 var camera = new BABYLON.UniversalCamera("camera", new BABYLON.Vector3(0,0, 5), scene);5 camera.setTarget(BABYLON.Vector3.Zero()); //设置观察目标6 camera.attachControl(canvas, true); //开启对Canvas的控制7 //创建半球光源,并指明其名字和光线投射方向8 var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1,0), scene);9 var material=new BABYLON.StandardMaterial("boxMaterial", scene); //创建材质10 material.diffuseTexture=new BABYLON.Texture("textures/crate.png", scene);//设置漫反射纹理11 var box1=BABYLON.MeshBuilder.CreateBox("box1", {height:3, width:3, depth:3},scene)12 box1.position.set(-3,0,0); //设置立方体1的位置13 box1.material=material; //设置立方体1的材质14 var box2=box1.clone(); //克隆网格对象15 box2.position.set(3,0,0); //设置立方体2的位置16 return scene; //返回场景对象17 };
❑ 第1~6行代码的功能为获取场景对象,创建通用相机并指定相机名字和位置,设置相机的观察目标位置。这样就完成了场景和通用相机的创建。
❑ 第7~16行代码的功能为创建半球光源并指明其名字和光线投射的方向,创建材质并设置材质的漫反射纹理,创建两个立方体并放置在场景的不同位置。
弧度旋转相机始终指向给定的目标位置 ,并且可以围绕该目标旋转,目标作为旋转中心。示例如下:
1 var createScene = function () {//创建场景方法2 var scene = new BABYLON.Scene(engine); //创建场景3 //创建弧形旋转摄像机,并指定它的初始纵向旋转角度、初始横向旋转角度和旋转半径以及观察目标位置4 var camera = new BABYLON.ArcRotateCamera("Camera", 3 * Math.PI / 2,5 Math.PI / 8, 20, BABYLON.Vector3.Zero(), scene);6 camera.attachControl(canvas, true); //添加控制7 camera.lowerRadiusLimit = 6; //设置最低旋转半径8 camera.upperRadiusLimit = 20; //设置最高旋转半径9 camera.useAutoRotationBehavior = true; //设置自动旋转10 //创建半球光源,并指定光源方向11 var light = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1,0), scene);12 var material=new BABYLON.StandardMaterial("boxMaterial", scene); //创建材质13 material.diffuseTexture=new BABYLON.Texture("textures/crate.png", scene);//设置漫反射纹理14 var box1=BABYLON.MeshBuilder.CreateBox("box1", {height:3, width:3, depth:3},scene);15 box1.position.set(3,0,0); //设置立方体1的位置16 box1.material=material; //设置立方体1的材质17 var box2=box1.clone(); //克隆立方体1的网格对象18 box2.position.set(-3,0,0); //设置立方体2的位置19 return scene; //返回场景对象20 }
❑ 第1~9行代码的功能为创建场景对象,创建弧形旋转相机并指定初始纵向旋转角度、初始横向旋转角度和旋转半径以及观察目标的位置,开启对Canvas的控制和设置相机的最低旋转半径、最高旋转半径和开启相机自动旋转。
❑ 第10~19行代码的功能为创建半球光源并指明其名字和光线投射方向,创建材质并设置材质的漫反射纹理和创建两个立方体并放置在场景的不同位置。
跟随相机是跟随目标运动改变位置而改变位置的相机,当目标网格对象的位置发生变化时,相机 会跟随目标网格对象改变位置。示例如下:
1 var createScene = function () { //创建场景的方法2 var scene = new BABYLON.Scene(engine); //获取场景对象3 var camera = new BABYLON.FollowCamera("FollowCam",4 new BABYLON.Vector3(0, 10, -10), scene); //创建跟随相机5 camera.radius = 30; //设置相机与目标网格对象的距离6 camera.heightOffset = 10; //设置相机的高度偏移7 camera.rotationOffset =0; //设置相机在 xOy平面上的角度偏移8 camera.cameraAcceleration = 0.005 //设置相机在移动目标位置上的加速度9 camera.maxCameraSpeed = 10 //设置相机的最大速度10 camera.attachControl(canvas, true); //开启控制11 var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1,0), scene);12 var mat = new BABYLON.StandardMaterial("mat1", scene); //创建材质13 var texture = new BABYLON.Texture("textures/crate.png", scene); //加载纹理14 mat.diffuseTexture = texture; //设置漫反射纹理15 var box = BABYLON.MeshBuilder.CreateBox("box", {size: 2}, scene);16 box.position = new BABYLON.Vector3(20, 0, 10); //设置立方体的位置17 box.material = mat; //设置立方体的材质18 var boxesSPS = new BABYLON.SolidParticleSystem("boxes", scene, {updatable:false});19 var set_boxes = function(particle, i, s) { //设置立方体位置函数20 particle.position = new BABYLON.Vector3(-50 + Math.random()*100, -50 +Math.random()*100,21 -50 + Math.random()*100); }22 boxesSPS.addShape(box, 400, {positionFunction:set_boxes}); //向粒子系统中添加400个立方体23 var boxes = boxesSPS.buildMesh(); //粒子系统创建网格对象24 camera.lockedTarget = box; //设置相机的目标网格对象25 var alpha = 0; //立方体运动角度26 var orbit_radius = 20; //立方体运动半径27 scene.registerBeforeRender(function () { //渲染之前执行的函数28 alpha +=0.01; //更改运动角度29 box.position.x = orbit_radius*Math.cos(alpha); //更改立方体的 x位置30 box.position.y = orbit_radius*Math.sin(alpha); //更改立方体的 y位置31 box.position.z = 10*Math.sin(2*alpha); //更改立方体的 z位置32 camera.rotationOffset = (18*alpha)%360; //更改摄像机的旋转偏移33 });34 return scene; };
❑ 第1~9行代码的主要功能为获取场景对象和创建跟随相机,以及设置相机与目标网格对象的距离、相机的高度偏移、相机在xOy平面上的角度偏移和相机移动到目标位置的加速度。
❑ 第10~16行代码的主要功能为创建标准材质并设置它的漫反射纹理,创建立方体网格对象并设置它的位置和材质。
❑ 第17~23行代码的主要功能为创建粒子系统,向粒子系统中添加400个立方体网格对象并设置每个立方体网格对象的位置。粒子系统创建网格对象以及将跟随相机的观察目标指向带有纹理贴图的立方体网格对象。需在目标网格对象之后,指定跟随相机的目标时。
❑ 第24~31行的代码主要功能为不断改变立方体网格对象的位置使跟随相机跟随其运动,同时也要不断改变相机的旋转偏移,以呈现出更好的相机跟随效果。
(3)网格对象
自带的网格对象包括 立方体、球体、圆柱体、曲面细分多边形等,创建网格对象时,最大的不同就是options参数的不同。options是一个参数数组,包含这个网格对象的构建信息。示例如下:
1 var createScene = function () {2 var scene = new BABYLON.Scene(engine); //创建场景和摄像机3 var camera = new BABYLON.ArcRotateCamera("camera1", 0, 0, 0,4 new BABYLON.Vector3(0, 0, -0), scene); //创建摄像机5 camera.setPosition(new BABYLON.Vector3(0,30,35)); //设置摄像机的位置6 camera.attachControl(canvas, true); //开启摄像机控制7 var light = new BABYLON.PointLight("light", new BABYLON.Vector3(30,30,20),scene);8 light.intensity = 0.7; //设置光照强度9 var meshArray=[]; //网格对象数组10 meshArray.push(BABYLON.MeshBuilder.CreateBox("box",11 {height:6, width:6, depth:6}, scene)) //新建立方体12 meshArray.push(BABYLON.MeshBuilder.CreateSphere("sphere",13 {diameter: 5}, scene)) //新建球体14 meshArray.push(BABYLON.MeshBuilder.CreateCylinder("cone",15 {diameterTop: 0, diameterBottom:6, height:5, tessellation: 8}, scene))//新建圆柱体16 meshArray.push( BABYLON.MeshBuilder.CreatePlane("plane",17 {width: 4, height:4, sideOrientation:BABYLON.Mesh.DOUBLESIDE}, scene))//新建平面18 meshArray.push(BABYLON.MeshBuilder.CreateDisc("disc",19 {radius:4, tessellation: 3, sideOrientation:BABYLON.Mesh.DOUBLESIDE}, scene))20 meshArray.push(BABYLON.MeshBuilder.CreateTorusKnot("tk", {}, scene));//新建圆环结21 meshArray.push(BABYLON.MeshBuilder.CreateTorus("torus",22 {diameter:5, thickness:1.5}, scene)); //新建圆环23 meshArray.push(BABYLON.MeshBuilder.CreateGround("gd",24 {width: 6, height:6, subdivsions:4}, scene)); //新建地面25 var groundMaterial = new BABYLON.StandardMaterial("groundMaterial", scene);26 var ground =BABYLON.MeshBuilder.CreateGround("gd",27 {width: 40, height:15 , subdivsions: 4}, scene); //创建地板28 ground.material = groundMaterial; //设置地板的材质QQQ:
29 var meshMaterial=new BABYLON.StandardMaterial("meshMaterial", scene)//创建材质30 for(var i=0; i<meshArray.length; i++){ //遍历网格对象数组31 meshArray[i].material=meshMaterial; //指定网格对象的材质32 meshArray[i].material.diffuseColor=new BABYLON.Color3(1, Math.random(), Math.random());33 meshArray[i].position.x=-16+Math.floor(i/2)*10; //指定网格对象的x位置34 meshArray[i].position.y=4; //指定网格对象的y位置35 meshArray[i].position.z=(i%2==0)? -4:6; //指定网格对象的z位置36 }37 return scene; //返回场景对象38 };
❑ 第1~8行代码的功能为创建场景、摄像机和光照等基本组件。读者可能对摄像机和光照的知识不熟悉,不要担心,这些知识将在下文进行详细介绍。
❑ 第9~24的代码为新建不同的网格对象,包括立方体、球体、圆柱体、圆环结和圆环等,然后将其放进网格对象数组进行管理,以及创建地板并指定地板的材质。
❑ 第25~37行代码的功能为遍历网格对象数组,指定各个网格对象的材质并设置材质的漫反射颜色,指定各网格对象的x、y、z坐标,最后返回场景对象。
高度图网格对象就是根据灰度图中各个像素的灰度值计算出地形的顶点坐标数据,示例如下:
1 //创建标准材质,并指定其漫反射纹理2 var groundMaterial=new BABYLON.StandardMaterial("groudMaterial", scene);3 groundMaterial.diffuseTexture=new BABYLON.Texture("textures/ground.jpg", scene)4 //根据高度图创建网格对象,指定灰度图的宽度和高度以及细分数量,设置地形的最大高度5 var ground = BABYLON.MeshBuilder.CreateGroundFromHeightMap("gdhm",6 "textures/default.png", {width:257, height :257, subdivisions:257,maxHeight: 128}, scene);7 ground.material=groundMaterial;
本段代码的功能为创建标准材质并指定其漫反射纹理,根据高度图创建网格对象并指定灰度图的宽度和高度以及细分数量,设置地形的最大高度,最后指定高度图网格对象的材质。