用 Babylon.js 和 JavaScript 写 3D 游戏——从入门到精通(2)

By | 2023/01/29

上一章节,我们学习了如何用babylonjs来创建一个简单的场景,我们最终得到了一个颇为美丽的结果:有棋盘格的地面,一个玻璃球体,我们可以自由的旋转他们,并且也能看到一点光线的效果。

只不过,整个过程充满了晦涩的代码和一些不明所以的参数,好像懂了又好像完全不懂。为了能够更好的进入3D的世界,我们在这一章节需要把所有需要了解的 API 和基础知识进行一些讲解,以便后面更好地了解和深入我们的知识体系。

在创建一个3D世界之前,我们要做的就是创建一个场景scene,所谓场景就是一个可以放置模型,灯光和摄像机的舞台。当然,场景并不仅仅是放置这些东西,它也可以放置一些比如用户UI等部件,甚至多个场景可以互相叠加来实现更高级的效果。

Camera

接下来说说摄像机,Babylon.js 中有很多不同的摄像机。我们最常用的两种是通用摄像机(Universal Camera)和旋转摄像机(ArcRotateCamera), 前者主要用于第一人称视角随着角色移动, 后者主要是围绕着一个中心点进行旋转观察。 Babylon JS最近也引入了一个叫WebXRCamera的摄像机。主要用于在虚拟现实中使用。

ArcRotateCamera 是我们之前使用的摄像机。它的主要特性就是镜头永远指向一个指定的点,而且可以围绕那个点进行旋转,它可以通过方向键和鼠标进行控制。把这个摄像机想象为观察物体的卫星。比如,就是像是观察地球的月亮一样,月亮相对于地球的位置,可以使用3个参数来控制。

  • alpha (经度,弧度制)
  • beta (纬度,弧度制)
  • radius (距离,这里是离地心的距离)

整个想象图是这样的:

注意beta是顺时针方向的,而alpha是逆时针方向。 而且,出于技术上的一些限制,beta为0或者pi会导致一些视觉上的问题,所以如果设置了0表示正上方的话,可能实际上beta是0.1。

当使用鼠标键盘进行控制时, 左右方向会改变alpha,法上下方向会改变beta, 鼠标滚轮就会修改radius。这个摄像机一般的初始化方法如下:

// 参数: 名称, alpha, beta, radius, target 位置, scene
const camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 10, new BABYLON.Vector3(0, 0, 0), scene);

// 如果重新设置位置,将会重置 alpha, beta, radius
camera.setPosition(new BABYLON.Vector3(0, 0, 20));

// 将摄像机绑定到canvas
camera.attachControl(canvas, true);

当然,ArcRotateCamera还有很多其他有用的参数和方法。 我们会在合适的地方时候来讲述,包括其他种类的摄像机,我们后面用到的时候再详细讨论。

灯光

光在现实世界中是极其重要的,同样灯光在3D世界中是非常重要的存在,没有合适的光影效果,人眼是很难在2D的屏幕上感知出3D效果。

BabylonJS中有4种常用的光源都挺重要的,所以下面都介绍一下。

点光源 (Point Light)

点光就是在 3D 世界中确定一个点,光从这个点向各个方向发射。其实就和现实世界中的电灯泡是类似的。

const light = new BABYLON.PointLight("pointLight", new BABYLON.Vector3(1, 10, 1), scene); // 参数: 名称,点光的位置,场景

平行光(Directional Light)

平行光就是由完全方向定义的一束,并且它具有无限的照射范围。可以参考现实里的太阳光,虽然太阳本质是个点光源,但是它太远了,到底到地球时我们感受到的阳光近似就是平行的。

const light = new BABYLON.DirectionalLight("DirectionalLight", new BABYLON.Vector3(0, -1, 0), scene); // 第二个参数是平行光的方向

聚光灯(Spot Light)

聚光灯就像时摄影现场的聚光灯,或者说它是一种特殊的点光源,只朝向某一个方向照射。它的参数有一个位置,一个照射方向,发散的角度和光强,比点光源多了两个参数。

// 前三个参数与点光源已有,第4个参数是发散的角度,第5个参数指数exponent指的是偏离中心衰减的速度
const light = new BABYLON.SpotLight("spotLight", new BABYLON.Vector3(0, 30, -10), new BABYLON.Vector3(0, -1, 0), Math.PI / 3, 2, scene);


着重说明下第五个参数exponent,因为聚光灯的能量有限会形成一个照射范围,光照中心到范围的边界,光是不断衰减的,exponent正是用来控制衰减的速度的,当exponent越大时,衰减速度越快。给一张图会比较明显一些。

可以看到光线在向边界扩散时迅速变暗了

半球光(Hemispheric Light)

半球光是BabylonJS中特有的一种说法,对很多其他3D引擎中,一般会存在一种环境光AmbientLight,本质都是模拟环境光的方式。它由一个方向参数定义,位于世界坐标中心(0,0,0),一般设置灯光方向朝正上方。不过这个方向参数其实并不重要,主要还是要通过设置颜色来改变整体环境光的氛围。

const light = new BABYLON.HemisphericLight("HemiLight", new BABYLON.Vector3(0, 1, 0), scene); // 第2个参数是向上的方向

光的颜色和强度

与我们想象的不太相同,在Babylon JS中,光的颜色通过可以3个参数来指定。

light.diffuse = new BABYLON.Color3(1, 0, 0); // 漫反射颜色,适用于所有灯光类型
light.specular = new BABYLON.Color3(0, 1, 0); // 高光颜色,适用于所有灯光类型
light.groundColor = new BABYLON.Color3(0, 1, 0);  // 地光颜色,仅适用于半球光

图中的小球是被半球光渲染的效果,红色就是漫反射的颜色,红色中的一个小亮点就是高光的颜色,而最下面的绿色是的光的颜色。

光强其实前面的例子也有了,通过 light 的 intensity 属性设置,1为默认值,数值越大,光线越强烈。

当然,光的知识也并不仅仅是这些而已。比如光照的法向设置、光照贴图、阴影,或者说是从光照中排除一些面不产生效果等 ,后面我们会继续不停地更新我们的知识。

快速创建一个场景

通过上面的学习我们知道了。要搭建一个3D场景,那么模型、场景、摄像机和光源是必不可少的要素。为了能够让我们快速的搭建出这样的一个测试或者验证场景,BabylonJS提供了一系列的辅助方法,可以让我们更快的搭建验证想法,最后我们就用这样一个快速搭建的方法代码来结束这次的教程。

var createScene = function () {
    var scene = new BABYLON.Scene(engine); // 场景搭建和以往一样

    var cube = BABYLON.MeshBuilder.CreateBox("box", {}); // 我们直接放置两个立方体
    cube.position.y = 5;
    var cube2 = BABYLON.MeshBuilder.CreateBox("box", {}); // 把他们的位置稍微错开一些
    cube2.position.x = -5;

    scene.createDefaultCameraOrLight(true, true, true); // 创建“默认”的摄像机和灯光
    scene.createDefaultEnvironment(); // 这句可以没有,其实就是创建出一个天空盒,或者可以认为是视野的边界

    return scene;
};

createDefaultCameraOrLightcreateDefaultCamera 两个函数是用来快捷创建摄像机的,并且它会根据场景中已经存在的物体进行适当的放置来保证所有的物体都能被看到。而且createDefaultCameraOrLight这个名字其实有点奇怪,它本质是createDefaultCameraAndLight 😀。

这两个函数都接受三个参数,都是布尔值,且默认值都是false,他们的含义是:

  • createArcRotateCamera: 默认创建一个FreeCamera,如果是true就创建一个ArcRotateCamera;
  • replace: 如果为true,就用这个刚创建的摄像机替换任何已有的激活摄像机;
  • attachCameraControls: 如果为true,就绑定到canvas上(这样鼠标才能操作)

很明显,createDefaultCameraOrLight = createDefaultCamera + createDefaultLight,默认创建的光就是半球光。

3 thoughts on “用 Babylon.js 和 JavaScript 写 3D 游戏——从入门到精通(2)

发表评论

您的电子邮箱地址不会被公开。