babylonjs是用于3D网页游戏开发的WEBGL插件,微软开发和维护的web端3D引擎。
- 官网地址
- 中文地址
babylonjs提供了很多很好用的工具,结合这些工具使用起来会比较容易上手。
Babylon.js提供了一个在线编辑器,它叫做The Playground,它是制作自己场景的最快捷,最简单的方法。
playground地址
界面很简单,左侧是代码区域,右侧是场景预览区域。编写完成后点击执行代码按钮即可实时预览场景。同时还可以单击下载按钮将代码下载下来。
sanbox工具主要是用于将三维模型导入,然后通过它可以看到当前模型的s素材组成部分、或者自带动画(如果有的话),简而言之,它是一个模型预览工具。
sanboxd地址
界面如下:
将模型文件拖拽至界面中或者点击右下角按钮选择文件即可。
这个我将要一个obj文件传入,效果如下:
然后我们点击第一个查看详情按钮,弹出左右两个弹窗。
第一个Nodes节点中我们可以看到这个模型由四部分组成:Object059、Object060、Object061、Sphere020。这里我们把第一个碎片隐藏了。在开发过程中,我们也可以通过代码去获得这几个碎片,具体代码在下面的章节进行介绍。
纹理文件,通过右侧面板可以添加纹理。
diffuse texture 漫反射纹理
specular texture 高光纹理
reflection texture 反射纹理
…
加载的贴图文件。这里暂时不知道为什么没有在场景中显示出来。
babylonjs也提供了很多在线例子可以查看,可以结合文档学习。同时也可以下载项目源码,在本地网页进行查看。
在线文档和例子
从上面sandbox的初始化界面的【drag and drop gltf,glb,obj or babylon files to view them】,我们可以知道,babylonjs支持gltf,glb,obj以及babylon着四种文件格式。
其中,babylonjs内置模型格式是babylon格式,不需要其他插件即可加载。但如果使用的是其他格式的文件,则需要babylonjs-loaders插件进行加载,否则网页会提示报错无法显示。
由于我在项目中(也就是上述sandbox中使用的文件)使用的是obj模型文件,这里就记录下obj文件情况吧。
.obj文件:
.mtl文件
下面的项目使用笔记基于vue项目。
babylon的文件包有很多,项目中可以根据自己的需要进行加载:
还有很多其他的可以在官网上进行查阅。
而我在项目中主要用到:
import * as BABYLON from "babylonjs"; // 主包
import "babylonjs-loaders"; // 用于加载obj模型
html中创建canvas元素作为挂载:
<canvas id="renderCanvas">canvas>
const canvas = document.getElementById("imgCanvas");
const engine = new BABYLON.Engine(canvas, true, {
preserveDrawingBuffer: true,
stencil: true
});
const scene = new BABYLON.Scene(engine);
// 相机有几种(可查看官网),此处我创建的是是旋转相机
const camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 10, BABYLON.Vector3.Zero(0, 0, 0), scene);
camera.attachControl(canvas, true);
// 点光源
const light1 = new BABYLON.PointLight("pointLight", new BABYLON.Vector3(1, 10, 1), scene);
// 方向光
const light2 = new BABYLON.DirectionalLight("DirectionalLight", new BABYLON.Vector3(0, -1, 0), scene);
// 聚光灯
const light3 = new BABYLON.SpotLight("spotLight", new BABYLON.Vector3(0, 30, -10), new BABYLON.Vector3(0, -1, 0), Math.PI / 3, 2, scene);
// 环境光
const light4 = new BABYLON.HemisphericLight("HemiLight", new BABYLON.Vector3(0, 1, 0), scene);
导入模型也是项目中最重要的部分。导入模型有两种方法:
模型相关文件都放在一个文件夹中,也就是a.obj、a.jpg、a.mtl在同一文件夹路径。
配置项:
文件夹路径,资源名称,场景对象,成功回调函数
BABYLON.SceneLoader.Append("./", "a.obj", scene, function (scene) {
// 模型添加成功后的回调函数
console.log(scene);
});
这里我们将scene场景对象打印出来,对象上有很多属性和方法:cameras场景相机、lights场景灯光、meshes模型碎片、animationGroups动画等等…
其中meshes就是我们在sanbox中可以查看到的四个模型碎片:
其中数组的每一项中的id属性值即该碎片的名字。
既然可以拿到这些属性,那我们就可以对其进行一些操作:
BABYLON.SceneLoader.Append("./obj/", "a.obj", scene, function (scene) {
// 模型添加成功后的回调函数 返回scene场景对象
console.log(scene);
const animation = scene.animationGroups;
animation[0].stop(); // 停止动画
animation[0].start(); // 开始动画
const meshes = scene.meshes;
meshes[0].isVisible = false; // 隐藏Sphere020碎片
meshes[0].isVisible = true; // 显示Object059碎片
meshes[1].rotation.x = 2; // 将碎片进行旋转
meshes[2].position.y = 2; // 改变位置
// ...
// 还有很多可操作项目 可查看官方文档
});
importMesh和append最大的不同的地方是,append返回的是scene场景对象,而importMesh返回的是模型对象。
配置项:
素材名称(为空表示所有模型或者骨骼)、文件夹路径、资源名称、场景对象、成功回调函数
BABYLON.SceneLoader.ImportMesh("", "./obj/", "a.obj", scene, function (meshes, particleSystems, skeletons) => {
// 模型添加成功后的回调函数 返回meshes模型对象、粒子、骨架
console.log(meshes);
})
BABYLON.SceneLoader.AppendAsync("./obj/", "a.obj", scene).then(newScene => {
...
})
engine.runRenderLoop(() => {
scene.render()
})
<template>
<div class="play">
<canvas id="imgCanvas"></canvas>
</div>
</template>
<script>
import * as BABYLON from "babylonjs";
import "babylonjs-loaders";
export default {
name: "Play",
mounted() {
this.scene();
},
methods: {
scene() {
const canvas = document.getElementById("imgCanvas");
// 加载3D引擎
const engine = new BABYLON.Engine(canvas, true, {
preserveDrawingBuffer: true,
stencil: true
});
// 创建场景对象
const scene = new BABYLON.Scene(engine);
// 创建旋转相机
const camera = new BABYLON.ArcRotateCamera(
"Camera", 0, 0, 10, BABYLON.Vector3.Zero(0, 0, 0), scene
);
camera.attachControl(canvas, true);
BABYLON.SceneLoader.Append("./obj/", 'a.obj', scene, scene => {
scene.createDefaultCameraOrLight(true, true, true); // 默认光源
// ...
});
// 画布上重复渲染场景
engine.runRenderLoop(() => {
scene.render();
});
}
}
</script>
场景默为蓝色背景,通过clearColor可以改变背景颜色,此处我将背景颜色opacity值设为0,达到透明背景的效果。
scene.clearColor = new BABYLON.Color4(0, 0, 0, 0);
默然情况下,场景镜头是可以缩放的。在移动端上通过双指触摸可看到放大缩小效果。如果想禁止此功能,可以通过camera镜头上的属性进行设置。
let myCamera = scene.cameras[0];
myCamera.lowerRadiusLimit = myCamera.radius;
myCamera.upperRadiusLimit = myCamera.radius;
默认情况下,场景镜头是可以移动的。在移动端上通过双指触摸可看到画布移动效果。
scene.activeCamera.panningSensibility = 0;
项目中遇到的最大的困难便是模型的灯光问题,在场景中添加默认灯光的情况下,模型如下:
然而现在的模型材质没有光感,于是我在场景中再添加了一个从下往上的方向光:
let light = new BABYLON.DirectionalLight("Dir0", new BABYLON.Vector3(0, 1, 0), scene); // 方向y: 1 从下往上
但是场景中却没有什么变化,即使换成其他类型的光、其它方向的光也没有效果。
这个问题着实困扰到自己了,经过各种查询,才找到大致问题所在,那就是材质对光的反应。
使用diffuseTexture、specularTexture、emissiveTexture以及ambientTexture等属性中的一个或多个来设置一个材质的纹理。其中,ambientTexture只有在没有设置场景环境颜色的时候才被使用。
var myMaterial = new BABYLON.StandardMaterial("myMaterial", scene);
myMaterial.diffuseTexture = new BABYLON.Texture("a.jpg", scene);
myMaterial.specularTexture = new BABYLON.Texture("a.jpg", scene);
myMaterial.emissiveTexture = new BABYLON.Texture("a.jpg", scene);
myMaterial.ambientTexture = new BABYLON.Texture("a.jpg", scene);
scene.ambientColor = new BABYLON.Color3(1, 1, 1); // 场景环境颜色
mesh.material = myMaterial;
设置完成后的效果如下:
不过加上灯光材质之后,模型材质的感觉就不太一样的,显得很光滑。
个人觉得灯光这块还有很多没有弄明白的地方,希望以后的项目中能进一步学习到吧~
真是要加油学习呢~
[1]: 基于babylon.js的3D网页游戏从零教程
[2]: 举个例子网:babylonjs教程