Babylon.js-3 基本元素

参考链接:https://doc.babylonjs.com/babylon101/discover_basic_elements

BABYLON使用左手笛卡尔坐标系,如图所示:

我们可以通过Babylon中的MeshBuilder来创建基本元素,其通用写法为

1
const mesh = BABYLON.MeshBuilder.Create<Mesh>(name, {param1 : val1, param2: val2 ,...otherParam }, scene);

其中<Mesh>可以有如下选择

  • Box (盒子)
  • Cylinder (圆柱)
  • DashedLines (虚线)
  • Decal (贴花)
  • Disc (圆盘)
  • Ground (地面)
  • GroundFromHeightMap (在高度图上的地面)
  • IcoSphere (多边形近似球体)
  • Lathe (车床)
  • LineSystem (线系统)
  • Lines (线)
  • Plane (平面)
  • Polygon (多边形)
  • Polyhedron (多面体)
  • Ribbon (丝带)
  • Sphere (球)
  • TiledBox (平铺盒子)
  • TiledGround (平铺地面)
  • TiledPlane (平铺平面)
  • Torus (花托)
  • TorusKnot (圆环结)
  • Tube (管道)

参考 MeshBuilder API

盒子 (Box)

1
const box = BABYLON.MeshBuilder.CreateBox("box", parameters, scene);

其中parameter是盒子的可选参数,如下:

  • backUVs?: Vector4 反面UV坐标
  • depth?: number 深度(沿z轴)
  • faceColors?: Color4[] 面颜色
  • faceUV?: Vector4[] 面UV坐标
  • frontUVs?: Vector4 正面UV坐标
  • height?: number 高度(沿y轴)
  • sideOrientation?: number 边方向
  • size?: number 尺寸
  • updatable?: boolean 是否可更新
  • width?: number 宽度(沿x轴)
updatablesideOrientation是大部分Create函数的parameter参数的共有属性。
Vector4 是Babylon.js的4维向量类
Color4 是Babylon.js的rgba颜色类,取值为[0,1]
  • size 指盒子的尺寸,当width height depth未设置时都使用size值代替。
  • faceUV 指盒子的面UV坐标,当盒子使用材质渲染时,该坐标作为材质贴图划分的标志。该数组的元素顺序为后前右左上下。
  • faceColors 指盒子的面颜色,同faceUV顺序。
  • frontUVs backUVs 指正反面的UV坐标,当盒子正反面都渲染时(由sideOrientation决定),区分前后的UV坐标。
  • updatable 指是否可以更新(顶点或者颜色等)
  • sideOrientation 指正反面的方向,默认为BABYLON.Mesh.DEFAULT,可选值为BABYLON.Mesh.FRONTSIDE,BABYLON.Mesh.BACKSIDE,BABYLON.Mesh.DOUBLESIDE。考虑性能原因,BABYLON会在默认情况下只渲染前面,可以修改该参数实现只渲染后面或两面都渲染。

我们可以通过一个例子来说明盒子元素。为简单起见,先不考虑贴图以及顶点更新之类的东西,光照也和热身章节中的一样,我们改变一下摄像机位置以便观察。假设有一个盒子,大小是0。我们让其每一帧长度,宽度,高度分别加1,2,3,然后到达100,200,300后再每一帧减去1,2,3。并且给盒子的前面设置为绿色,给盒子上面设置为红色,其他面均为白色。我们可以用以下代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const canvas = document.getElementById('renderCanvas-3-1')
const engine = new BABYLON.Engine(canvas,true)
const scene = new BABYLON.Scene(engine)
// 添加照相机
const camera = new BABYLON.ArcRotateCamera("Camera",-Math.PI/4,Math.PI/3, 500, new BABYLON.Vector3(0,0,0), scene)
// 设置照相机可以控制
camera.attachControl(canvas, false)
// 添加光源
const light1 = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(1, 1, 0), scene)
const light2 = new BABYLON.PointLight("light2", new BABYLON.Vector3(0, 1, -1), scene)
// TODO 修改代码为假设效果
// 设置变化方向
let x=true,y=true,z=true
let width=0,height=0,depth=0
let box = null
// 创建动画效果
const anime=()=>{
width+=(x?1:-1)*1
height+=(x?1:-1)*2
depth+=(x?1:-1)*3
if(width>=100){
x=false
}else if(width<=0){
x=true
}
if(height>=200){
y=false
}else if(height<=0){
y=true
}
if(depth>=300){
z=false
}else if(depth<=0){
z=true
}
// 注意! 此处使用移除场景中的box再新添加box来实现视觉上box大小的变化,如果改变原始box,需要修改其顶点坐标来实现。设置updatable为true,之后修改mesh的顶点坐标。
if(box!==null){
scene.removeMesh(box)
//注意释放资源
box.dispose()
}
box=BABYLON.MeshBuilder.CreateBox("box",{width,height,depth,faceColors:[new BABYLON.Color4(1,1,1),new BABYLON.Color4(0,1,0),new BABYLON.Color4(1,1,1),new BABYLON.Color4(1,1,1),new BABYLON.Color4(1,0,0),new BABYLON.Color4(1,1,1)]},scene)
requestAnimationFrame(anime)
}
anime()
engine.runRenderLoop(function(){scene.render()})

效果如下:

我们看到有些面的颜色是黑色或者灰色,是由于该面没有光照造成的,在接下来的光照章节中将会介绍。

球 (Sphere)

1
const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", parameters, scene);

其中parameter是球的可选参数,如下:

  • arc?: number [0,1],默认值:1,创建圆周的arc倍的不完整球
  • backUVs?: Vector4 反面UV坐标
  • diameter?: number 直径
  • diameterX?: number x轴直径
  • diameterY?: number y轴直径
  • diameterZ?: number z轴直径
  • frontUVs?: Vector4 正面UV坐标
  • segments?: number 默认值:32,分段数
  • sideOrientation?: number
  • slice?: number [0,1],默认值:1,创建高度的slice倍的不完整球
  • updatable?: boolean
  • diameter 指球的直径,当diameterX diameterY diameterZ未设置时都使用diameter值代替。
  • segments 指球的分段数,值越大分段越多越精密,但越消耗内存。

假设一个球的半径为2,分段数为8,使用以下代码进行实验:

1
2
3
4
5
6
7
8
9
10
11
12
13
const canvasSphere = document.getElementById('renderCanvas-3-sphere')
const engineSphere = new BABYLON.Engine(canvasSphere,true)
const sceneSphere = new BABYLON.Scene(engineSphere)
// 添加照相机
const cameraSphere = new BABYLON.ArcRotateCamera("CameraSphere",-Math.PI/4,Math.PI/3, 5, new BABYLON.Vector3(0,0,0), sceneSphere)
// 设置照相机可以控制
cameraSphere.attachControl(canvasSphere, false)
// 添加光源
const lightSphere1 = new BABYLON.HemisphericLight("lightSphere1", new BABYLON.Vector3(1, 1, 0), sceneSphere)
const lightSphere2 = new BABYLON.PointLight("lightSphere2", new BABYLON.Vector3(0, 1, -1), sceneSphere)
// TODO 修改代码为假设效果
const sphere=BABYLON.MeshBuilder.CreateSphere("sphere",{diameter:2,segments:8},sceneSphere)
engineSphere.runRenderLoop(function(){sceneSphere.render()})

效果如下:

平面 (Plane)

1
const plane = BABYLON.MeshBuilder.CreatePlane("plane", parameters, scene);

其中parameter是平面的可选参数,如下:

  • backUVs?: Vector4
  • frontUVs?: Vector4
  • height?: number 高度
  • sideOrientation?: number
  • size?: number 尺寸
  • sourcePlane?: Plane
  • updatable?: boolean
  • width?: number 宽度
  • size 指平面的尺寸,当width height 未设置时都使用size值代替。
  • 可以理解为一个盒子的前面。

我们创建一个宽为2,高为1的平面,使用以下代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
const canvasPlane = document.getElementById('renderCanvas-3-plane')
const enginePlane = new BABYLON.Engine(canvasPlane,true)
const scenePlane = new BABYLON.Scene(enginePlane)
// 添加照相机
const cameraPlane = new BABYLON.ArcRotateCamera("CameraPlane",-Math.PI/4,Math.PI/3, 5, new BABYLON.Vector3(0,0,0), scenePlane)
// 设置照相机可以控制
cameraPlane.attachControl(canvasPlane, false)
// 添加光源
const lightPlane1 = new BABYLON.HemisphericLight("lightPlane1", new BABYLON.Vector3(1, 1, 0), scenePlane)
const lightPlane2 = new BABYLON.PointLight("lightPlane2", new BABYLON.Vector3(0, 1, -1), scenePlane)
// TODO 修改代码为假设效果
const plane=BABYLON.MeshBuilder.CreatePlane("plane",{width:2,height:1},scenePlane)
enginePlane.runRenderLoop(function(){scenePlane.render()})

效果如下:

Ground (地面)

1
const ground = BABYLON.MeshBuilder.CreateGround("ground", parameters, scene);

其中parameter是地面的可选参数,如下:

  • height?: number 高 z轴
  • subdivisions?: number 边的细分数
  • subdivisionsX?: number x轴边细分数
  • subdivisionsY?: number y轴边细分数
  • updatable?: boolean
  • width?: number 宽 x轴
  • Ground是创建在x轴和z轴(y=0)的地面。
  • subdivisions是地面边的细分数,用于构建高度图。默认subdivisionsX subdivisionsYsubdivisions相同。
    我们创建一个宽为2,高为1的地面,并简单标注一下坐标轴,使用以下代码实现:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    const canvasGround = document.getElementById('renderCanvas-3-ground')
    const engineGround = new BABYLON.Engine(canvasGround,true)
    const sceneGround = new BABYLON.Scene(engineGround)
    // 添加照相机
    const cameraGround = new BABYLON.ArcRotateCamera("CameraGround",Math.PI/3,Math.PI/4, 4, new BABYLON.Vector3(0,0,0), sceneGround)
    // 设置照相机可以控制
    cameraGround.attachControl(canvasGround, false)
    // 添加光源
    const lightGround1 = new BABYLON.HemisphericLight("lightGround1", new BABYLON.Vector3(1, 1, 0), sceneGround)
    const lightGround2 = new BABYLON.PointLight("lightGround2", new BABYLON.Vector3(0, 1, -1), sceneGround)
    // TODO 修改代码为假设效果
    const lineXGround=BABYLON.Mesh.CreateLines("lineXGround",[new BABYLON.Vector3(0,0,0),new BABYLON.Vector3(1,0,0)],sceneGround)
    const lineYGround=BABYLON.Mesh.CreateLines("lineYGround",[new BABYLON.Vector3(0,0,0),new BABYLON.Vector3(0,1,0)],sceneGround)
    const lineZGround=BABYLON.Mesh.CreateLines("lineZGround",[new BABYLON.Vector3(0,0,0),new BABYLON.Vector3(0,0,1)],sceneGround)
    const ground=BABYLON.MeshBuilder.CreateGround("ground",{width:2,height:1},sceneGround)
    lineXGround.color=new BABYLON.Color3(1,0,0)
    lineYGround.color=new BABYLON.Color3(0,1,0)
    lineZGround.color=new BABYLON.Color3(0,0,1)
    engineGround.runRenderLoop(function(){sceneGround.render()})

效果如下: