# babylon.js **Repository Path**: yunxia/babylon.js ## Basic Information - **Project Name**: babylon.js - **Description**: babylon.js学习笔记 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2022-08-10 - **Last Updated**: 2022-08-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # babylon.js [参考文档]: https://doc.cnbabylon.com/babylon101/ ## 1.关于babylon Babylon.JS使用了HTML5的canvas元素作为容器,可以非常方便的在Web上进行3D编程。 > Babylon.js与非常著名的three.js类似,都是构建在webGL之上,用于实现3d效果,Babylon.js的优势在于很多有用的功能都是原生提供,并且社区非常活跃,在里面提问都会得到回复,而且playground提供的演示也非常方便,最近发布的新版本还提供了ios、windows、android的原生执行环境,所以我们很看好babylon未来的发展。 ## 2.迈出第一步 - 让babylon运行起来 ### 在线运行 [Playground](https://playground.cnbabylon.com/)是一个专为babylon打造的类似codeOpen或者jsfiddle的在线代码编辑器,你可以在里面进行任意的实验,创建任意的3d场景,保存并分享给其他人,也可以查看和编辑其它人分享的3d场景,是一个学习babylon编程的利器。[这是更多关于playground的介绍](https://endoc.cnbabylon.com/features/playground) ```js // 初始化一个场景,engine是Playground准备好的默认参数 var scene = new BABYLON.Scene(engine); // 添加一个相机,并绑定鼠标事件 var camera = new BABYLON.ArcRotateCamera( "Camera", Math.PI / 2, Math.PI / 2, 2, BABYLON.Vector3.Zero(), scene ); camera.attachControl(canvas, true); // 添加2个灯光到场景中 var light1 = new BABYLON.HemisphericLight( "light1", new BABYLON.Vector3(1, 1, 0), scene ); var light2 = new BABYLON.PointLight( "light2", new BABYLON.Vector3(0, 1, -1), scene ); // 添加一个球体到场景中 var sphere = BABYLON.MeshBuilder.CreateSphere( "sphere", { diameter: 2 }, scene ); //Playground中必须返回一个创建好的场景实例 return scene; ``` Playground会准备好执行环境,你不必考虑babylon怎么引入,HTML怎么写,canvas如何的摆放,只需要专心处理核心逻辑,相当于Playground帮你处理好了所有食材,接下来只需要下锅就行, [这是上面的代码在Playground中展示的效果](https://playground.cnbabylon.com/#9M3PE4) ### 搭建自己的HTML执行环境 自己从零开始搭建babylon执行环境,这是把babylon引入到自己项目中的必经之路,你需要考虑更多的东西,例如如何引入babylon的js文件,并且在平板电脑和手机上,BabylonJS使用pointer事件而不是mouse事件,因此也需要加载PEP.js。 此外,首先需要把canvas添加到body中,它决定了3d场景的渲染位置,然后我们还需要把这个canvas引入到我们的JavaScript代码中,用它来初始化babylon引擎,得到一个engine对象,使用这个engine对象来创建我们的3d场景scene。 最后,还有一个很重的步骤,让scene开始执行渲染,Playground中不需要这一步,因为它在已经为我们自动做了。所以这导致很多人会忽略这一步,觉得自己初始化了场景,加入了物体,效果就出来了,但是场景却出不来。这一步的关键就是调用engine对象的runRenderLoop方法,让scene在这个方法中进行60fps的不间断渲染,而且也可以让3d场景自动适应画布的大小,在我们改变浏览器窗口大小的时候,做到大小自适应。 ~~~html Babylon Template //touch-action="none" for best results from PEP ~~~ ### 注意事项 1. 上面的栗子都使用了 **MeshBuilder** 方法来创建形状物体,相比旧的 **BABYLON.Mesh.Create** 创建方式更加方便。因为历史原因,以前有很多Playground中的栗子都使用了 **BABYLON.Mesh.Create** 方法来创建物体,我们更加推荐 **MeshBuilder** 方法。 2. 在pointer事件的兼容处理中,babylon以前是使用 **hand.js** ,但是它的作者已经不再维护,所以改为了使用 **PEP.js** 来实现,目前两者都可以正常运行。 ## 3. 如何引用Babylon.js到项目中 ### 介绍 首先我们把babylon核心文件以及补充组件做一个简单的罗列和介绍。 - **babylonjs** - babylon的核心库,引入它就能让程序跑起来,下面的是功能补充的库 - **babylonjs-materials** - 集合了babylon官方提供的一组高级材质,提供更炫酷的效果 - **babylonjs-loaders** - 能够让babylon支持导入OBJ, STL, glTF等3d文件 - **babylonjs-post-process** - 后期特效库,能够让场景展示电影级别的滤镜效果 - **babylonjs-procedural-textures** - babylon官方提供的一组纹理贴图,可以展示更酷的效果 - **babylonjs-serializers** - 能够把场景Scene和物体mesh等元素序列化成为json配置并导出. - **babylonjs-gui** - 交互组件库,支持按钮、复选框、下拉列表等表单元素 - **babylonjs-inspector** - 对babylon的3d场景进行运行时调试,可详细记录并显示babylon甚至webGL的运行情况,非常强大 - **babylonjs-viewer** - Babylon查看器,几行代码就能让3d内容展示到网页上。 ### cdn #### 稳定版本 ##### 未压缩版 - **babylonjs** : https://cdn.cnbabylon.com/babylon.max.js - **babylonjs-materials** : https://cdn.cnbabylon.com/materialsLibrary/babylonjs.materials.js - **babylonjs-loaders** : https://cdn.cnbabylon.com/loaders/babylonjs.loaders.js - **babylonjs-post-process**: https://cdn.cnbabylon.com/postProcessesLibrary/babylonjs.postProcess.js - **babylonjs-procedural-textures** : https://cdn.cnbabylon.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.js - **babylonjs-serializers** : https://cdn.cnbabylon.com/serializers/babylonjs.serializers.js - **babylonjs-gui** : https://cdn.cnbabylon.com/gui/babylon.gui.js - **babylonjs-inspector** : https://cdn.cnbabylon.com/inspector/babylon.inspector.bundle.js ##### 压缩版 - **babylonjs** : https://cdn.cnbabylon.com/babylon.js - **babylonjs-materials** : https://cdn.cnbabylon.com/materialsLibrary/babylonjs.materials.min.js - **babylonjs-loaders** : https://cdn.cnbabylon.com/loaders/babylonjs.loaders.min.js - **babylonjs-post-process** : https://cdn.cnbabylon.com/postProcessesLibrary/babylonjs.postProcess.min.js - **babylonjs-procedural-textures** : https://cdn.cnbabylon.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js - **babylonjs-serializers** : https://cdn.cnbabylon.com/serializers/babylonjs.serializers.min.js - **babylonjs-gui** : https://cdn.cnbabylon.com/gui/babylon.gui.min.js ##### 引用示例 ```html ``` ### 预览版 只要把 **cdn.cnbabylon.com** 替换为 **preview.cnbabylon.com** 就可以了 ##### 引用示例 ``` ``` ### NPM ### ES5 要安装ES5版本请使用以下代码 ```shell npm install --save-dev babylonjs npm install --save-dev babylonjs-materials npm install --save-dev babylonjs-loaders npm install --save-dev babylonjs-post-process npm install --save-dev babylonjs-procedural-textures npm install --save-dev babylonjs-serializers npm install --save-dev babylonjs-gui npm install --save-dev babylonjs-viewer ``` ### ES6 ES6的安装在babylon文件名前面多加了一个 **@** 符号,并且后面的 **-** 变成了 **/** ```shell npm install --save-dev @babylonjs/core npm install --save-dev @babylonjs/materials npm install --save-dev @babylonjs/loaders npm install --save-dev @babylonjs/post-processes npm install --save-dev @babylonjs/procedural-textures npm install --save-dev @babylonjs/serializers npm install --save-dev @babylonjs/gui npm install --save-dev @babylonjs/viewer ``` ### 安装其他版本的babylon 只需要在模块后面加入 **@** 并指定一个版本号即可 #### ES5: ``` npm install --save-dev babylonjs@4.1.0-rc.8 ``` #### ES6: ``` npm install --save-dev babylonjs/core@4.1.0-rc.8 ``` ### 引入模块 #### ES5: ``` import * as BABYLON from 'babylonjs'; //全部引入 import { Engine, Scene } from 'babylonjs'; //只引入使用到的类 import * as Materials from 'babylonjs-materials';//引入其他模块中的所有类,例如materials材质库 ``` #### ES6: ``` import * as BABYLON from '@babylonjs/core/Legacy/legacy'; //全部引入 import {Engine, Scene } from '@babylonjs/core'; //只引入使用到的类 import "@babylonjs/materials/legacy/legacy"; //引入其他模块中的所有类,例如materials ``` > 请注意上面的例子中ES5和ES6引入官方扩展库的方式区别: > ES5使用import * as Materials from 'babylonjs-materials',把所有组件挂在了Materials中,使用方法为:var skyMaterial = new Materials.SkyMaterial(.....) > ES6使用import "@babylonjs/materials/legacy/legacy",把所有组件挂在了BABYLON中,使用方法为:var skyMaterial = new BABYLON.SkyMaterial(.....) > 当然ES6和ES5都支持按需导入,例如ES5 import { SkyMaterial } from 'babylonjs-materials',ES6:import { Engine } from '@babylonjs/core/Engines/engine' ### 注意事项 1. 通过npm install安装的babylon模块,默认是安装稳定版本,如果想体验最新功能,请参照[安装其他版本的babylon](https://doc.cnbabylon.com/3-0-how-to-get-babylon-js/#3-3)来指定最新版本的babylon模块。 2. inspector和viewer模块属于独立功能的组件,平时开发可以不用引入。 ## babylon官方GitHub 你也能够按照下列文件路径直接指向[babylon的repo](https://github.com/BabylonJS/Babylon.js): - 稳定版[/dist/](https://github.com/BabylonJS/Babylon.js/tree/master/dist) - 预览版[/dist/preview release/](https://github.com/BabylonJS/Babylon.js/tree/master/dist/preview release) - 旧版本[/dist/previous release/](https://github.com/BabylonJS/Babylon.js/tree/master/dist/previous releases) ## 4. 了解基本形状物体及其要素 ### 常规形状 有一些基本的形状是我们在日常生活中经常遇到的,例如:盒子(立方体)、球体、圆柱、圆锥、规则多边形(三面体、四面体)、平面以及地面(一种特殊的水平平面)。还有一些形状比上面那些知名度差一点的,包括:圆环、环形节以及多面体等,它们其实也包含在常规形状中,我们将在本章介绍上述这些常规形状。而还有一些可能并是很常见的形状,我们将在接下来的[第5章具有参数化形状的物体](http://doc.cnbabylon.com/5-0-parametric-shapes/)中进行介绍,它们没有固定的形状,一般需要设置对应数据集或者参数才能画出来,例如:线条、线段、挤压形状、车床形状等。 babylon101是作为babylon的入门课程,所以在本章中只介绍几个最基本的常规形状物体,包括:立方体、球体、平面和地面。此外,我们在课程中会使用 **MeshBuilder** 方法来创建物体,可能你在Playground中会接触到老版本 **BABYLON.Mesh.Create** 的创建方法,这个方法已经淘汰,所以请特别的注意。关于两个方法的优缺点以及详细介绍各位也可以到[延伸阅读](https://doc.cnbabylon.com/4-0-discover-basic-elements/#3)中去进一步探索。 ### MeshBuilder方法介绍 创建一个形状的通用语句如下: ```js var shape = BABYLON.MeshBuilder.CreateShape(name, options, scene);//CreateShape中的Shape可替换为想要创建的物体名称 ``` 第一个参数表示这个物体的名称,第三个参数是加入到的场景scene变量,我们重点介绍第二的参数 **options** 可以为物体设置一些体积、长宽、是否可更改等参数,具体针对每种形状的创建示例和 **options** 参数说明如下: #### 立方体Box ```js // 创建默认立方体 var box = BABYLON.MeshBuilder.CreateBox("box", {}, scene); // 设置长宽高并创建 var myBox = BABYLON.MeshBuilder.CreateBox("myBox", {height: 5, width: 2, depth: 0.5}, scene); ``` | option | 值类型&说明 | 默认值 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ----------------------------------------- | | size | (number) 立方体每一面的大小,也就是长宽高统一都是这个值 | 1 | | height | (number) 单独设置高度Y,覆盖size的高度 | size | | width | (number) 单独设置长度X,覆盖size的长度 | size | | depth | (number) 单独设置宽度Z,也称为深度,覆盖size的长度 | size | | [faceColors](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-2) | (Color4[]) 是一个长度为6的数组,代表立方体的6个面,可以对其分别设置[Color4](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-7)颜色 | 每个面默认Color4(1, 1, 1, 1) | | [faceUV](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-2) | (Vector4[]) 是一个长度为6的数组,代表立方体的6个面,可以对其分别设置纹理贴图的应用范围[Vector4](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-6),类似background-position | 每个面默认Vector4(0, 0, 1, 1) | | [updatable](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-3) | (boolean) 如果设置为true,则表示该物体的顶点数据可以被更新 | false | | [sideOrientation](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-4) | (number) 物体可被看到的面 | 默认0,正面,可选:0 正面,1 背面,2 双面 | #### 球体Sphere ``` // 创建默认球体 var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {}, scene); // 设置直径并创建 var mySphere = BABYLON.MeshBuilder.CreateSphere("mySphere", {diameter: 2, diameterX: 3}, scene); ``` | option | 值类型&说明 | 默认值 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ----------------------------------------- | | segments | (number) 水平分段数,决定了球体的精度,值越小棱角就越明显 | 32 | | diameter | (number) 球体通用直径,相当于XYZ方向都是同一个值 | 1 | | diameterX | (number) X轴直径, 覆盖diameter的X方向的值 | diameter | | diameterY | (number) Y轴直径, 覆盖diameter的X方向的值 | diameter | | diameterZ | (number) Z轴直径, 覆盖diameter的X方向的值 | diameter | | arc | (number) 圆周率(纬度方向切割),取值范围0到1,0.5相当于一个半球 | 1 | | slice | (number) 高度比 (经度方向切割),取值范围0到1,与arc类似,只是切割方向不一样 | 1 | | [updatable](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-3) | (boolean) 如果设置为true,则表示该物体的顶点数据可以被更新 | false | | [sideOrientation](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-4) | (number) 物体可被看到的面 | 默认0,正面,可选:0 正面,1 背面,2 双面 | #### 平面Plane ```js // 创建默认平面 var plane = BABYLON.MeshBuilder.CreatePlane("plane", {}, scene); // 设置宽高并创建 var myPlane = BABYLON.MeshBuilder.CreatePlane("myPlane", {width: 5, height: 2}, scene); ``` | option | 值类型&说明 | 默认值 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ----------------------------------------- | | size | (number) 平面长度和高度,统一都是这个值,默认是个正方形 | 1 | | width | (number) 单独设置长度X,覆盖size的高度 | size | | height | (number) 单独设置高度Y,覆盖size的高度 | size | | [updatable](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-3) | (boolean) 如果设置为true,则表示该物体的顶点数据可以被更新 | false | | [sideOrientation](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-4) | (number) 物体可被看到的面,3D世界的计算比较耗费资源,一般相机移动到物体的背面,为了节省资源就默认不显示这个物体了 | 默认0,正面,可选:0 正面,1 背面,2 双面 | | [frontUVs](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-5) | (Vector4) 仅当sideOrientation设置为双面时可用,和faceUV的作用类似,因为平面没有深度只有2个面,只能按照这个方法来设置正面,类似background-position | Vector4(0,0, 1,1) | | [backUVs](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-5) | (Vector4) 仅当sideOrientation设置为双面时可用,和faceUV的作用类似,因为平面没有深度只有2个面,只能按照这个方法来设置背面,类似background-position | Vector4(0,0, 1,1) | | sourcePlane | (Plane) 一种平面的定位方法,可以更改平台的位置和角度,这也可以用position和rotation来实现 | null | 只有平面有sourcePlane这个选项,它提供了一种方法,用于修改平面的位置和方向,如果想让平面朝向某一个固定方向,这个方法挺有用。举个例子,现在我们只考虑平面的方向,在初始化时平面默认的方向是[vector3](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-6)(0,0,1)。如果希望把方向调整为vector3(0,-1,1),则使用如下代码: ~~~js var sourcePlane = new BABYLON.Plane(0, -1, 1, 0); sourcePlane.normalize(); ~~~ 以上代码创建了一个用于定位方向的计算辅助平面。第4个参数是在方向轨道上移动的距离,在例子中设置为0,表示不移动。下面我们来看看效果演示: [Playground 平面使用sourcePlane参数实例](https://playground.cnbabylon.com/#NWIPL5#3) #### 地面Ground ```js var ground = BABYLON.MeshBuilder.CreateGround("ground", {}, scene); //default ground var myGround = BABYLON.MeshBuilder.CreateGround("myGround", {width: 6, height: 4, subdivisions: 4}, scene); ``` | option | 值类型&说明 | 默认值 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------ | | width | (number) 地面的长度 | 1 | | height | (number) 地面的宽度,这里与平面有区别,默认创建的时候地面是水平的,而平面是垂直的 | 1 | | [updatable](https://doc.cnbabylon.com/4-0-discover-basic-elements/#1-3) | (boolean) 如果设置为true,则表示该物体的顶点数据可以被更新 | false | | subdivisions | (number) 细分数,可以把地面进行等分,就像瓷砖那样每一块都有同一个图案 | 1 | [Playground 创建地面的实例](https://playground.cnbabylon.com/#NWIPL5#4) 还有一种特殊的地面,我们称之为[高低图](http://doc.cnbabylon.com/babylon101/Height_map),它让平坦的地面产生了有山谷的地形效果。 ### FaceColors和FaceUV详解 顾名思义,Face代表物体的面,所以FaceColors和FaceUV只能用在具有面的物体上,例如立方体,而球体就没有这两个选项。FaceColors能够设置物体每个面的颜色,而FaceUV与纹理贴图有很大的关系,这类似于[css sprite](https://baike.baidu.com/item/css sprite/1139316?fr=aladdin),可以把一张图的不同部分展示到物体的每个面上。更详细的内容[请看这里](http://doc.cnbabylon.com/how_to/createbox_per_face_textures_and_colors) [Wikipedia上有关UV贴图的更多介绍](https://en.wikipedia.org/wiki/UV_mapping) ### Updatable可更新形状的物体 Babylon中的物体都是由一组顶点数据经过彼此之间的连接构成,如果一个物体Option中的updatable参数设置为true,那么这个物体的顶点数据就能够被修改,这意味着物体能够改变形状。有关更详细的内容,可以看这里[怎么样更新顶点](http://doc.cnbabylon.com/how_to/updating_vertices) ### SideOrientation选项 3D世界的计算比较耗费资源,一般相机移动到物体的背面,为了节省资源就默认不显示这个物体了,所以在创建物体时SideOrientation都为正面。如果选择反面,那么当相机位于物体的正面时,物体就被隐藏了。如果选择了双面,无论相机如果移动,那么物体都会被显示出来,这也是最耗费电脑资源的方式。 SideOrientation有4个可能的选项: - BABYLON.Mesh.FRONTSIDE,表示正面。 - BABYLON.Mesh.BACKSIDE,表示反面。 - BABYLON.Mesh.DOUBLESIDE,表示双面。 - BABYLON.Mesh.DEFAULT,目前这个值和FRONTSIDE相等 各位可能比较奇怪,SideOrientation在参数说明里不是接受的是数字么?怎么在这里变成了 **BABYLON.Mesh.FRONTSIDE** 这种形式。其实这是Babylon提供的一种易于阅读的参数类,各位可以在控制台自己打印一下。BABYLON.Mesh.FRONTSIDE的值是0,BACKSIDE是1,DOUBLESIDE是2,DEFAULT也是1。在下面的例子中,大家可以通过左右移动鼠标来改变相机位置,比较一下正面和双面两种设置的异同: [Playground 显示正面的平面示例](https://playground.cnbabylon.com/#NWIPL5#5) [Playground 显示双面的平面示例](https://playground.cnbabylon.com/#NWIPL5#6) ### FrontUV和BackUV 之前的段落介绍了FaceUV的使用,FrontUV和BackUV与它类似,都是用来把一张图的不同部分展示到物体的每个面上,但不同的是FrontUV和BackUV只用在只有正反面的物体上,例如平面,FrontUV用来设置正面,而BackUV用来设置反面。而请大家注意,只有当SideOrientation选项设置为双面时,这两个选项才能够起作用。各位可以从[应用不同的材质到物体的正反面](http://doc.cnbabylon.com/how_to/frontandbackuv)来查看更详细的介绍。 ### Vect3和Vect4 向量是3D世界中的基本单位,Vect3表示三维向量,也叫作三元数。Vect4表示四维向量,也叫作四元数。Vect3用得比较多,例如位置、旋转、放大缩小都使用了Vect3,用它来表示X、Y、Z 这3个不同的坐标。而Vect4一般用来做三维空间的旋转变换,具体可以看看知乎的一篇科普文章[如何形象地理解四元数?](https://www.zhihu.com/question/23005815/answer/33971127) ```js var position = new BABYLON.Vect3(1,1,1);//三维向量 var quaternion = new BABYLON.Vect4(1,1,1,1);//四维向量 ``` ### Color3和Color4 顾名思义,这代表了颜色,Color3表示rgb,Color4表示rgba,只是Babylon中的Color值都是用0至1表示的,例如Color3(0.5,0.5,0.5),就相当于rgb(128,128,128)。 ```js var rgb = new BABYLON.Color3(0.5, 0.5, 0.5);//颜色 var rgba = new BABYLON.Color3(0.5, 0.5, 0.5, 1);//透明度颜色 ``` ## 5. 具有参数化形状的物体 ### 参数化形状 在本章我们介绍一种特殊的形状,它们需要设置对应数据集或者参数才能画出来,包括:线条、线段系统、缎带、管子、挤压形状、车床形状以及不规则多边形等。由于101课程只是为入门者准备的,所以这里我们不打算深入太多,本章只是抛砖引玉的介绍一下线条的使用。此外,我们在课程中会使用 **MeshBuilder** 方法来创建物体,可能你在Playground中会接触到老版本 **BABYLON.Mesh.Create** 的创建方法,这个方法已经淘汰,所以请特别的注意。关于两个方法的优缺点以及创建所有参数化形状的方法,各位请移步到[延伸阅读](https://doc.cnbabylon.com/5-0-parametric-shapes/#3)中去进一步探索。 ### 线条Lines 在3D世界中,线条由一系列分割的线段组成,它们首尾相连的排列在一起。从具体创建上来说,线条是由一系列的点组成。 例如 (0, 0, 0), (0, 1, 1), (0, 1, 0) 这三个点会形成2条线段,把线段进行首尾相连,最后会形成一个弯折的线条。 在Babylon中,这些点由是三维向量表示,会由 **BABYLON.Vect3** 对象进行初始化,然后把初始化好的点按顺序形成数组,最后传递给CreateLines进行线条的绘制。 ~~~js //可以先初始化一个数据 var myPoints = []; //然后初始化三个点,push到数组里 var point1 = new BABYLON.Vector3(0, 0, 0); myPoints.push(point1); var point2 = new BABYLON.Vector3(0, 1, 1); myPoints.push(point2); var point3 = new BABYLON.Vector3(0, 1, 0); myPoints.push(point3); //也可以直接这样写 var myPoints = [ new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1, 1), new BABYLON.Vector3(0, 1, 0) ]; ~~~ 由点组成的二维数组myPoints,我们需要把他作为Option中的points对象传递给CreateLines函数。 ~~~js //创建一个线条 var lines = BABYLON.MeshBuilder.CreateLines("lines", {points: myPoints}, scene); ~~~ [Playground 创建一个线条](https://playground.cnbabylon.com/#BNY2YC) [Playground 创建一个DNA螺旋线](https://playground.cnbabylon.com/#BNY2YC#1) 你也可以用CreateDashedLines创建一条虚线,它比创建普通线条多出了三个选项:dashNb、dashSize、gapSize,可以定制虚线的样式。 CreateLines方法的 **options** 参数说明如下: | option | 值类型&说明 | default value | | -------------- | ------------------------------------------------------------ | ------------- | | points | (Vector3[]) 点的数组,绘制线条所需的点路径 | null | | updatable | (boolean) 如果设置为true,则表示该物体的顶点数据可以被更新 | false | | instance | (LineMesh) 接受另一个线条的实例,把其Option导入到这里来 | null | | colors | (Color4[]) 颜色的数组,一般与points一 一对应,定义每个点的颜色,两点之间线段的颜色由前一个点确定 | null | | useVertexAlpha | (boolean) 如果设置为false,则线条不支持透明度,会节省资源,增加渲染速度 | true | #### Updatable可更新形状的物体 线条和虚线也有Updatable选项,假如设置为true,如果为真,则可以更改与线的每个顶点之间相关联的数据,从而进一步改变线条的路径。有关更详细的内容,可以看这里[怎么样更新顶点](http://doc.cnbabylon.com/how_to/updating_vertices) #### Instance选项 线条里有一个Instance选项,这个方法可以通过传递一组新的Points来更新线条的样式,形象的说也就是让线条可以扭动起来。首先我们要把Updatable设置为true,然后把新的点初始化为一个线条并传入到Instance中。请注意,新的点必须和之前点的数量保持一致,也就是Points数组的长度必须是一样的。 ```js //首先创建一个线条 var lines = BABYLON.MeshBuilder.CreateLines("lines", {points: myArray, updatable: true}, scene); //然后把上面的线条作为一个instance传入到新创建的线条中,完成更新,新线条可以不用传入Scene实例,也就是第三个参数不用传。注意myArray和myNewArray长度必须一致。 lines = BABYLON.MeshBuilder.CreateLines("lines", {points: myNewArray, instance: lines}); ``` [Playground DNA螺旋线应用Instance实例](https://playground.cnbabylon.com/#BNY2YC#2) 大多数(但不是所有)参数化形状都有Instance选项,因此都可以用这种方式更新它们的参数值。 #### Vect3和Vect4 向量是3D世界中的基本单位,Vect3表示三维向量,也叫作三元数。Vect4表示四维向量,也叫作四元数。Vect3用得比较多,例如位置、旋转、放大缩小都使用了Vect3,用它来表示X、Y、Z 这3个不同的坐标。而Vect4一般用来做三维空间的旋转变换,具体可以看看知乎的一篇科普文章[如何形象地理解四元数?](https://www.zhihu.com/question/23005815/answer/33971127) ```js var position = new BABYLON.Vect3(1,1,1);//三维向量 var quaternion = new BABYLON.Vect4(1,1,1,1);//四维向量 ``` #### Color3和Color4 顾名思义,这代表了颜色,Color3表示rgb,Color4表示rgba,只是Babylon中的Color值都是用0至1表示的,例如Color3(0.5,0.5,0.5),就相当于rgb(128,128,128)。 ```js var rgb = new BABYLON.Color3(0.5, 0.5, 0.5);//颜色 var rgba = new BABYLON.Color3(0.5, 0.5, 0.5, 1);//透明度颜色 ``` ### 延伸阅读 ### 基础-难度L1 [如何使用MeshBuilder方法来创建常规物体](http://doc.cnbabylon.com/How_To/Set_Shapes) [如何使用旧方法来创建常规物体](https://doc.babylonjs.com/How_To/Legacy_Set) [MeshBuilder与旧方法的比较](https://doc.babylonjs.com/features/Shapes#ways-of-creating-a-predefined-mesh) ## 6. 物体的位置和旋转 ### 位置Position,旋转Rotation和缩放Scaling Babylon101定位入门级课程,所以在本章只会介绍物体的位置Position, 旋转Rotation 和 缩放Scaling三个设置参数。更多有关改变物体位置、方向的方法请各位移步到[延生阅读](https://doc.cnbabylon.com/6-0-position-and-rotation/#2)中去进一步探索。 关于三种方法都需要一个 **坐标参照系** ,也就是让一个物体如何改变位置、旋转和缩放的规则。而且为了很好的让大家理解 **坐标参照系** ,我们使用了一个不规则形状,称为 **实验体** ,用来帮助我们理解位置、旋转和缩放。 ![image-20220219205100409](README.assets/1pilot.jpg) 实验体的样子,其实就是一个立方体加上圆锥体 ### 坐标参照系 Babylon.js使用了两种 **坐标参照系** ,即世界坐标系world和局部坐标系local,世界坐标系可以理解为:全局坐标系。世界坐标系的原点位置任何时候都是(0, 0, 0)不会被改变,而局部坐标系会随着物体位置、旋转、缩放的改变而改变。例如:一个物体的初始位置是(0, 0, 0),它世界坐标系和局部坐标系就都是(0, 0, 0),当这个物体移动到位置(0, 10, 0)的时候,也就是向上移动了10的距离,这个时候它世界坐标系还是(0, 0, 0)和局部坐标系是(0, 10, 0)。 在Playground例子的中,坐标的轴线都有标准的颜色标识,X轴为红色,Y轴为绿色,Z轴为蓝色。 创建物体时,物体的中心就在世界坐标的原点(0, 0, 0)处,其位置的值始终是一个相对于世界坐标原点的值。例如位置(0, 10, 0),就是相对于(0, 0, 0)网上偏离了10个单位。 之前也讲到,局部坐标是随着物体的移动而移动的,并且无论物体的位置、方向、大小如何,局部坐标的原点始终在会处于物体的中心。物体旋转和缩放需要一个支点,一般来说都是位于其局部坐标的原点,简单来说也就是该物体的中心,所以我们看到的效果就是中心缩放和中心旋转。如果想改变支点怎么办?比如地球绕着太阳旋转,支点就肯定不能是自身中心,强大的Babylon肯定是有办法的,那就是通过使用[变换节点TransformNode](https://doc.cnbabylon.com/6-0-position-and-rotation/#2)或[矩阵Matrix](https://doc.cnbabylon.com/6-0-position-and-rotation/#2)来为物体设置新的支点。 ### 向量Vectors 所有位置,旋转和缩放比例均使用三维矢量分别设置,设置的格式为:BABYLON.Vector3(x,y,z) ### 实验体The Pilot 在创建一个物体后,默认旋转角度为0,缩放比例为1,所以实验体的位置也显示在世界坐标的原点(0, 0, 0),而且世界坐标轴和局部坐标轴此时是重合在一起的。 ![2pilot1](README.assets/2pilot1.jpg) 带坐标轴的实验体 ### 位置Position 位置Position参照世界坐标轴来放置实验体,使用的是三维向量vector3 (x, y, z),局部坐标轴随着实验体的移动而移动。 ```js //常规设置 pilot.position = new BABYLON.Vector3(2, 3, 4); //或者,独立设置 pilot.position.x = 2; pilot.position.y = 3; pilot.position.z = 4; ``` 虽然局部坐标轴的位置发生了变化,但是它和世界坐标轴的方向是一致的。 ![3pilot1](README.assets/3pilot1.jpg) [Playground 物体位置的实例](https://playground.cnbabylon.com/#K6ICTG) ### 旋转Rotation 真香警告!在3D空间中处理旋转是非常棘手的,首先对一个物体应用多次旋转操作,而应用这些旋转操作的先后顺序可能会导致物体有着完全不同的方向,其次我们还需要知道使用的是世界坐标还是局部坐标,这也是在旋转中影响物体方向的因素之一。把旋转操作应用到3D模型上,这有很多通用准则。想了解Babylon.js中这些相关的准则,请移步[欧拉角和四元数](https://endoc.cnbabylon.com/resources/rotation_conventions)。虽然很难,但是功能却很强大!真香 在Babylon.js中对物体设置旋转的代码如下: ```js //常规设置 pilot.rotation = new BABYLON.Vector3(alpha, beta, gamma); //或者,独立设置 pilot.rotation.x = alpha; //围绕X轴旋转 pilot.rotation.y = beta; //围绕Y轴旋转 pilot.rotation.z = gamma; //围绕Z轴旋转 ``` 以上代码中的alpha, beta, and gamma是以弧度作为单位的,也就是说与我们平时所说的角度不一样,例如360°,有一个换算公式: > 1° = π /180 弧度 可能的疑问:上面代码中分别设置了alpha, beta, gamma,针对了X、Y、Z三个轴,而且之前又说了旋转操作的先后顺序和使用的坐标系会影响最终方向,那么你会问了“代码中的旋转操作设置了alpha、beta、gamma,那它们三个分别使用了世界坐标系还是局部坐标系?应用的顺序如何?” 其实对于Babylon.js中旋转,以下两个准则得出的结果都是一样的: #### 准则1-局部坐标系 对于局部坐标,物体以中心为原点并沿着其局部坐标轴进行旋转,旋转的顺序为Y、X、Z。如果我们按照三个不同方向正对着观察物体的旋转,那么它们的旋转方向都是逆时针。 下图中按照顺序展示了执行旋转操作后实验体的方位,图1.初始状态、 图2. 绕着局部坐标系Y轴旋转π/2弧度、图3. 围绕局部坐标系X轴旋转π/2弧度、图4. 围绕局部坐标系Z轴旋转了π/2弧度。 ![准则1图片1](README.assets/4-1pilotl.jpg) 图中较小的轴表示世界轴的方向,就是线中间有个小点,各位要仔细看。 #### 准则2-世界坐标系 又称为全局坐标系,与准则1的局部坐标相比,按照世界坐标对物体进行旋转:旋转中心点没有变,但是旋转轴线变了。 对于世界坐标,物体以中心为原点保持和之前一样,沿着与世界坐标轴进行旋转,旋转的顺序为Z、X、Y。如果我们按照三个不同方向正对着观察物体的旋转,那么它们的旋转方向都是逆时针。 下图中按照顺序展示了执行旋转操作后实验体的方位,图1.初始状态、 图2. 绕着世界坐标系Z轴旋转π/2弧度、图3. 围绕局部坐标系X轴旋转π/2弧度、图4. 围绕局部坐标系Y轴旋转了π/2弧度 ![准则2图片1](README.assets/5-1pilotw.jpg) [Playground 物体旋转实例](https://playground.cnbabylon.com/#K6ICTG#1) #### 总结 我们可以看到,无论以何种方式进行旋转,最后的结果始终是相同的。 以下代码产生的结果都相同: ```js pilot.rotation = new BABYLON.Vector3(alpha, beta, gamma); pilot.rotation.x = alpha; pilot.rotation.y = beta; pilot.rotation.z = gamma; pilot.rotation.z = gamma; pilot.rotation.x = alpha; pilot.rotation.y = beta; pilot.rotation.y = beta; pilot.rotation.z = gamma; pilot.rotation.x = alpha; ``` [Playground 物体改变位置、旋转、方向综合实例](https://playground.cnbabylon.com/#K6ICTG#2) ### 一系列的旋转操作 假如你想要进行一系列的旋转操作,例如先围绕x轴旋转,再围绕y轴旋转,最后围绕z轴旋转,这应该怎么办呢? 其实在babylon这很简单,使用[rotate方法](https://endoc.cnbabylon.com/features/position,_rotation,_scaling#rotate),可以自定义是作用于世界坐标系还是局部坐标系。使用addRotation方法,仅针对局部坐标系。 我们详细介绍下addRotation方法,它可以进行链式调用,接受3个弧度参数值,分别对应X、Y、Z三个坐标轴。用法如下所示: ```js mesh.addRotation(Math.PI/2, 0, 0).addRotation(0, Math.PI/2, 0).addRotation(0, 0, Math.PI/2); ``` 以下的图例,用addRotation展示了实现 **Playground 物体旋转实例** 中的旋转案例,还是以实验体作为参照,图1、初始状态,无旋转;图2、绕局部X轴旋转π/ 2;图3、再绕着局部Y轴旋转π/ 2;图4、最后绕着局部Z轴旋转π/ 2。 ![旋转操作图片1](README.assets/6-1pilota.jpg) 图中较小的轴表示世界轴的方向,就是线中间有个小点,各位要仔细看。 一般来说,mesh.addRotation(alpha,beta,gamma)只对其中1个参数设置弧度制,剩下2个设为0,要不然行为会很怪异(也不知道官方怎么考虑的),其中alpha是围绕局部x轴的旋转,beta是围绕局部y轴的旋转,gamma是围绕局部z轴的旋转。 ### RotationQuaternions方法介绍 还有一种旋转方法,那就是用[rotationQuaternions](https://endoc.cnbabylon.com/resources/rotation_conventions#quaternions)方法直接操作四元数 **Quaternions** ,这个方法很抽象、很难,但好处就是接近底层,让你随意发挥。但是需要注意,这种方法和之前介绍的方法是不能同时使用到一个物体上的,具体请看[这里](https://doc.babylonjs.com/resources/rotation_conventions#warning)。 ### 缩放Scaling 缩放相对来说比较简单,不存在需要处理世界坐标的问题,我们只需要按照如下方法来沿着局部坐标X、Y、Z轴进行旋转即可。 ~~~js //常规设置 mesh.scaling = new BABYLON.Vector3(scale_x, scale_y, scale_z); //或者,独立设置 mesh.scaling.x = 5; mesh.scaling.y = 5; mesh.scaling.z = 5; ~~~ 下图显示了围绕z轴旋转并沿局部y轴缩放的一个立方体。 ![缩放及旋转](README.assets/7scaling1.jpg) X轴为红色,Y轴为绿色,Z轴为蓝色。 ### 下一步 现在你应该知道如何在场景中创建一个物体,然后移动、旋转、缩放它了,但是你会发现创建的物体都长一个样,为了让他们变得更漂亮点,请阅读下一章[材质materials-美化你的物体](http://doc.cnbabylon.com/7-0-materials/)。 ### 延伸阅读 #### 功能 [位移、旋转、缩放详解](https://endoc.cnbabylon.com/features/position,_rotation,_scaling) ## 7. 材质-美化你的物体 ### 材质material 材质被用来覆盖在你的物体上,用来给物体上色或者贴图,要注意一般来说材质要配合灯光才能显示出效果,同一个材质是可以应用到多个物体上面去的。 #### 材质对光线的反应 无论是使用颜色还是纹理贴图来设置材质,它对光线的反射都有着不同的表现。 1. 漫反射 - 在灯光下看到的材质基本颜色或纹理 2. 镜面反射 - 在灯光照射下,高光给与材质的效果 3. 自发光 - 材质的颜色或纹理就像一个灯光那样可以对外发出效果 4. 环境 - 环境背光所照射出来的材质颜色或纹理 要看到漫反射和镜面反射的材质效果,必须要求创建至少一个光源。 要让环境背光照射出材质的环境颜色效果,还需要为场景设置一个环境颜色,如下所示: ```js scene.ambientColor = new BABYLON.Color3(1, 1, 1); ``` 材质还可以设置一个透明度,会产生一个半透明的效果,通过设置材质的alpha属性来实现,取值范围是[0, 1]。 ### 颜色Color 可以通过如下代码创建一个材质: ``` //第一个参数是材质名称,第二个是场景实例 var myMaterial = new BABYLON.StandardMaterial("myMaterial", scene); ``` 接下来我们可以使用漫反射颜色diffuseColor、镜面颜色specularColor、自发光颜色emissiveColor以及环境颜色ambientColor来设置材质颜色,这四个颜色可以同时设置也可以只设置其中某一个。再次强调,仅当场景的环境颜色已设置时,环境颜色才能看到效果。设置材质颜色的案例如下: ~~~js var myMaterial = new BABYLON.StandardMaterial("myMaterial", scene);//创建一个材质 myMaterial.diffuseColor = new BABYLON.Color3(1, 0, 1);//漫反射颜色 myMaterial.specularColor = new BABYLON.Color3(0.5, 0.6, 0.87);//镜面颜色 myMaterial.emissiveColor = new BABYLON.Color3(1, 1, 1);//自发光颜色 myMaterial.ambientColor = new BABYLON.Color3(0.23, 0.98, 0.53);//环境光颜色 mesh.material = myMaterial;//mesh是之前创建的物体 ~~~ #### 漫反射颜色示例 为了理解灯光照射在材质上时,材质漫反射颜色的反应,下面的Playground示例显示了不同颜色的材质,分别对白色、红色、绿色和蓝色[聚光灯Spot Light](https://doc.cnbabylon.com/7-0-materials/#衍生阅读)所反应出的效果。这里要注意的是灯光light也具有颜色,可以设置漫反射diffuse和镜面反射specular。 [Playground 材质颜色对灯光颜色的反应](https://playground.cnbabylon.com/#49MYZ7) 设置材质的颜色如下,分别对应下图中的四个位置: | | | | :------: | :------: | | 黄色材质 | 紫色材质 | | 青色材质 | 白色材质 | 下图中还可以看到白色,红色,绿色和蓝色的聚光灯Spot Light。 ![1spots1](README.assets/1spots1.png) > 各位看到这里可能会比较郁闷,咱们来捋一捋,示例中的地面Ground可以通过单选框来切换不同的漫反射颜色:黄色、紫色、青色、白色,而且聚光灯一共有四盏,颜色分别是:白色,红色,绿色和蓝色,也就是它们都设置了灯光的漫反射颜色。示例是让各位熟悉一下不同颜色的灯光照射在有不同漫反射颜色的地面下会产生什么视觉效果,这里有一个规律,当地面材质为白色的时候,灯光照射在地面都显示出了自身原有的颜色;而且白色那一盏灯,会照射出地面材质的原本颜色。这说明在babylon中白色是一个通透的颜色,就像透明一样,而黑色则相反,它完全会遮挡住其他颜色,至于其他中间色,则表现出了一些特殊的效果,大家可以慢慢观察。 #### 环境颜色示例 先上一个例子[Playground 环境颜色示例](https://playground.cnbabylon.com/#49MYZ7#1) 例子中设置了一个[半球光Hemispheric Light](https://doc.cnbabylon.com/7-0-materials/#2),并给它设置了红色漫反射diffuse和绿色底色groundColor,所有的球体都由这个半球光来照亮,首先左边第一个球体没有设置材质和其环境颜色、中间的球体设置了红色环境色的材质、右边的球体设置了绿色环境色的材质。各位别忘了,还要设置场景scene的环境色哦,这里我们设置成了白色,上面说到白色代表通透,所以球的材质环境色改变会立马得到体现,但是如果scene的环境色设置为了黑色,也就是Color3(0,0,0),那么各位可以想象得到,球体将一直体现灯光的颜色,无论自身的材质环境色设置为任何颜色,都将没有效果。 ![2ambient1](http://doc.cnbabylon.com/content/images/2020/04/2ambient1.png) #### 透明度示例 通过将材质的alpha属性设置为0(不可见)到1(不透明)可以实现透明度。 ```js myMaterial.alpha = 0.5; ``` [Playground 为材质设置alpha透明度](https://playground.cnbabylon.com/#49MYZ7#2) 纹理贴图Texture 可以使用一张图片来生成纹理,纹理必须配合材质来使用,首先新建一个材质: var myMaterial = new BABYLON.StandardMaterial("myMaterial", scene); 然后可以使用漫反射纹理diffuseTexture、镜面反射纹理specularTexture、自发光纹理emissiveTexture以及环境纹理ambientTexture来设置材质纹理贴图,这四个纹理可以同时设置也可以只设置其中某一个。注意:如果没有设置场景的环境颜色,环境纹理将没有效果。设置材质纹理的案例如下: ```js var myMaterial = new BABYLON.StandardMaterial("myMaterial", scene); //PATH TO IMAGE,表示图片的路径,其实也可以使用base64格式的图片。 myMaterial.diffuseTexture = new BABYLON.Texture("PATH TO IMAGE", scene); myMaterial.specularTexture = new BABYLON.Texture("PATH TO IMAGE", scene); myMaterial.emissiveTexture = new BABYLON.Texture("PATH TO IMAGE", scene); myMaterial.ambientTexture = new BABYLON.Texture("PATH TO IMAGE", scene); mesh.material = myMaterial; //记得设置物体的材质属性 ``` 注意,如果没有指定法线时,Babylon的标准材质将会自动计算并生成法线数组。 > 各位可能要问,法线是什么?在3D世界中,法线用来进行光照计算,也就是灯光照射到物体上的呈现效果。具体各位可以百度一下。