Vue.js - 集成Babylon.js构建三维可视化场景教程1(安装配置、基本用法)
作者:hangge | 2026-06-10 09:39
Babylon.js 是一个功能完备、工程化程度极高的 Web 3D 引擎,内置完整的渲染管线、相机系统、光照模型、PBR 材质、动画与物理支持,并且对 glTF / glb 等工业级三维模型格式有着良好的原生支持,非常适合用于构建复杂、长期演进的三维可视化系统。本文将演示如何在 Vue.js 项目中集成 Babylon.js,并创建一个简单的 3D 场景。


(3)运行效果如下:

一、安装配置与基本用法
1,安装配置
进入 Vue 项目目录,执行如下命令安装 Babylon.js 及相关依赖库。
# 安装 Babylon.js 核心库 npm install babylonjs --save # 安装 Babylon.js 加载器(用于加载3D模型) npm install babylonjs-loaders --save # 安装 GUI 库(可选,用于创建UI控件) npm install babylonjs-gui --save # 如果需要 inspector 工具(开发调试) npm install babylonjs-inspector --save-dev
2,基本用法
(1)下面是一个简单的使用样例,里面包含场景、相机、渲染器、光源、地面、一个立方体、一个圆柱体、一个球体、窗口缩放响应、资源销毁与动画循环管理等内容。
<template>
<div class="babylon-container">
<div ref="canvasContainer" class="canvas-container">
<canvas ref="renderCanvas" class="render-canvas"></canvas>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="loading-overlay">
<div class="loader">加载中...</div>
</div>
<!-- 场景信息 -->
<div class="scene-info">
<p>物体数量: {{ objectCount }}</p>
<p>FPS: {{ fps.toFixed(1) }}</p>
</div>
</div>
</template>
<script>
import * as BABYLON from 'babylonjs';
export default {
name: "BabylonScene",
data() {
return {
engine: null,
scene: null,
loading: true,
error: null,
objectCount: 0,
fps: 60,
};
},
mounted() {
this.initBabylon();
},
beforeDestroy() {
// 销毁组件时释放内存,防止内存泄漏
if (this.engine) {
this.engine.dispose();
}
window.removeEventListener("resize", this.onWindowResize);
},
methods: {
initBabylon() {
const canvas = this.$refs.renderCanvas;
// 1. 初始化渲染引擎
this.engine = new BABYLON.Engine(canvas, true,
{ preserveDrawingBuffer: true, stencil: true });
// 2. 创建场景
this.scene = this.createScene(this.engine, canvas);
// 3. 隐藏加载遮罩
this.loading = false;
// 4. 注册渲染循环
this.engine.runRenderLoop(() => {
this.scene.render();
this.fps = this.engine.getFps();
});
// 5. 监听窗口调整大小
window.addEventListener("resize", this.onWindowResize);
// 6. 初始化场景统计
this.updateSceneInfo();
},
createScene(engine, canvas) {
const scene = new BABYLON.Scene(engine);
// 设置背景颜色
scene.clearColor = BABYLON.Color3.FromHexString('#aaaaaa').toColor4();
// 添加摄像头 (ArcRotateCamera 允许用户绕着中心点旋转)
const camera = new BABYLON.ArcRotateCamera(
'camera',
-Math.PI / 2,
Math.PI / 3,
7,
BABYLON.Vector3.Zero(),
scene
);
camera.attachControl(canvas, true);
// 设置相机控制
camera.wheelPrecision = 50;
camera.lowerRadiusLimit = 2;
camera.upperRadiusLimit = 50;
// 添加灯光
const light1 = new BABYLON.HemisphericLight(
'light1',
new BABYLON.Vector3(1, 1, 0),
scene
);
const light2 = new BABYLON.DirectionalLight(
'light2',
new BABYLON.Vector3(0, -1, 1),
scene
);
light2.position = new BABYLON.Vector3(5, 10, 5)
light2.intensity = 0.3
// 添加地面
const ground = BABYLON.MeshBuilder.CreateGround(
'ground',
{ width: 5, height: 5 },
scene
);
const groundMaterial = new BABYLON.StandardMaterial('groundMaterial', scene);
groundMaterial.diffuseColor = new BABYLON.Color3(0.8, 0.8, 0.8);
ground.material = groundMaterial;
// 创建一个立方体
const box = BABYLON.MeshBuilder.CreateBox("box", { size: 1 }, scene);
box.position = new BABYLON.Vector3(-1.5, 0.75, 0);
// 给立方体上色
const material = new BABYLON.StandardMaterial("boxMat", scene);
material.diffuseColor = new BABYLON.Color3(0, 0.5, 1);
box.material = material;
// 创建一个球体
const sphere = BABYLON.MeshBuilder.CreateSphere(
'sphere',
{ diameter: 1 },
scene
);
sphere.position = new BABYLON.Vector3(0, 0.75, 0);
// 给球体上色
const sphereMaterial = new BABYLON.StandardMaterial('sphereMaterial', scene);
sphereMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.8, 0.2);
sphere.material = sphereMaterial;
// 创建一个圆柱体
const cylinder = BABYLON.MeshBuilder.CreateCylinder(
'cylinder',
{ height: 1, diameter: 1 },
scene
);
cylinder.position = new BABYLON.Vector3(1.5, 0.75, 0);
// 给圆柱体上色
const cylinderMaterial = new BABYLON.StandardMaterial('cylinderMaterial', scene);
cylinderMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.2, 0.8);
cylinder.material = cylinderMaterial;
// 添加动画
scene.onBeforeRenderObservable.add(() => {
const time = Date.now() / 1000;
box.rotation.y = time * 0.5;
sphere.position.y = 0.5 + Math.sin(time) * 0.2;
cylinder.rotation.x = time * 0.3;
});
return scene;
},
// 更新场景信息
updateSceneInfo() {
if (this.scene) {
this.objectCount = this.scene.meshes.length;
}
},
// 窗口大小变化处理
onWindowResize() {
if (this.engine) {
this.engine.resize();
}
},
},
};
</script>
<style scoped>
.babylon-container {
position: relative;
width: 100%;
height: 100%;
}
.canvas-container {
width: 100%;
height: 100%;
overflow: hidden;
}
.render-canvas {
width: 100%;
height: 100%;
display: block;
outline: none;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.loader {
color: white;
font-size: 18px;
}
.scene-info {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.6);
color: white;
padding: 10px 15px;
border-radius: 5px;
font-size: 14px;
}
.scene-info p {
margin: 5px 0;
}
</style>
(2)运行效果如下,立方体、圆柱体会在场景中自动不断地自转,而球体则会沿着 Y 轴上下反复移动。

(3)同时我们可以通过鼠标对三维场景进行直观交互,整体交互体验接近专业三维软件(如 CAD、建模工具)的操作方式:
- 按住鼠标左键拖动可围绕目标物体旋转视角,从不同角度观察模型。
- 滚动鼠标滚轮可实现视图的放大与缩小,即相机向目标点靠近或远离。
- 按住鼠标右键拖动可平移视角,使整个场景在屏幕中上下左右移动。

3,添加阴影
(1)上面样例我们发现,虽然我们在场景里添加了灯光,但是并没有在地面上显示出物体的阴影。这时由于 Babylon.js 的阴影机制需要显式开启,其中:
- 半球光(HemisphericLight)本身不支持投射阴影,它只用于环境漫反射,看起来“亮”,但永远不会产生阴影。
- DirectionalLight / SpotLight / PointLight 需要创建 ShadowGenerator,否则也不会有阴影。
(2)下面我对前面的代码做个改进,创建 ShadowGenerator,让物体“投射阴影”,并让地面“接收阴影”。
<template>
<div class="babylon-container">
<div ref="canvasContainer" class="canvas-container">
<canvas ref="renderCanvas" class="render-canvas"></canvas>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="loading-overlay">
<div class="loader">加载中...</div>
</div>
<!-- 场景信息 -->
<div class="scene-info">
<p>物体数量: {{ objectCount }}</p>
<p>FPS: {{ fps.toFixed(1) }}</p>
</div>
</div>
</template>
<script>
import * as BABYLON from 'babylonjs';
export default {
name: "BabylonScene",
data() {
return {
engine: null,
scene: null,
loading: true,
error: null,
objectCount: 0,
fps: 60,
};
},
mounted() {
this.initBabylon();
},
beforeDestroy() {
// 销毁组件时释放内存,防止内存泄漏
if (this.engine) {
this.engine.dispose();
}
window.removeEventListener("resize", this.onWindowResize);
},
methods: {
initBabylon() {
const canvas = this.$refs.renderCanvas;
// 1. 初始化渲染引擎
this.engine = new BABYLON.Engine(canvas, true,
{ preserveDrawingBuffer: true, stencil: true });
// 2. 创建场景
this.scene = this.createScene(this.engine, canvas);
// 3. 隐藏加载遮罩
this.loading = false;
// 4. 注册渲染循环
this.engine.runRenderLoop(() => {
this.scene.render();
this.fps = this.engine.getFps();
});
// 5. 监听窗口调整大小
window.addEventListener("resize", this.onWindowResize);
// 6. 初始化场景统计
this.updateSceneInfo();
},
createScene(engine, canvas) {
const scene = new BABYLON.Scene(engine);
// 设置背景颜色
scene.clearColor = BABYLON.Color3.FromHexString('#aaaaaa').toColor4();
// 添加摄像头 (ArcRotateCamera 允许用户绕着中心点旋转)
const camera = new BABYLON.ArcRotateCamera(
'camera',
-Math.PI / 2,
Math.PI / 3,
7,
BABYLON.Vector3.Zero(),
scene
);
camera.attachControl(canvas, true);
// 设置相机控制
camera.wheelPrecision = 50;
camera.lowerRadiusLimit = 2;
camera.upperRadiusLimit = 50;
// 添加灯光
const light1 = new BABYLON.HemisphericLight(
'light1',
new BABYLON.Vector3(1, 1, 0),
scene
);
const light2 = new BABYLON.DirectionalLight(
'light2',
new BABYLON.Vector3(0, -1, 1),
scene
);
light2.position = new BABYLON.Vector3(5, 10, 5)
light2.intensity = 0.3
// 添加阴影生成器(核心)
const shadowGenerator = new BABYLON.ShadowGenerator(1024, light2)
shadowGenerator.useBlurExponentialShadowMap = true
shadowGenerator.blurKernel = 32
// 添加地面
const ground = BABYLON.MeshBuilder.CreateGround(
'ground',
{ width: 5, height: 5 },
scene
);
const groundMaterial = new BABYLON.StandardMaterial('groundMaterial', scene);
groundMaterial.diffuseColor = new BABYLON.Color3(0.8, 0.8, 0.8);
ground.material = groundMaterial;
// 接收阴影
ground.receiveShadows = true
// 创建一个立方体
const box = BABYLON.MeshBuilder.CreateBox("box", { size: 1 }, scene);
box.position = new BABYLON.Vector3(-1.5, 0.75, 0);
// 给立方体上色
const material = new BABYLON.StandardMaterial("boxMat", scene);
material.diffuseColor = new BABYLON.Color3(0, 0.5, 1);
box.material = material;
// 创建一个球体
const sphere = BABYLON.MeshBuilder.CreateSphere(
'sphere',
{ diameter: 1 },
scene
);
sphere.position = new BABYLON.Vector3(0, 0.75, 0);
// 给球体上色
const sphereMaterial = new BABYLON.StandardMaterial('sphereMaterial', scene);
sphereMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.8, 0.2);
sphere.material = sphereMaterial;
// 创建一个圆柱体
const cylinder = BABYLON.MeshBuilder.CreateCylinder(
'cylinder',
{ height: 1, diameter: 1 },
scene
);
cylinder.position = new BABYLON.Vector3(1.5, 0.75, 0);
// 给圆柱体上色
const cylinderMaterial = new BABYLON.StandardMaterial('cylinderMaterial', scene);
cylinderMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.2, 0.8);
cylinder.material = cylinderMaterial;
// 投射阴影
shadowGenerator.addShadowCaster(box)
shadowGenerator.addShadowCaster(sphere)
shadowGenerator.addShadowCaster(cylinder)
// 添加动画
scene.onBeforeRenderObservable.add(() => {
const time = Date.now() / 1000;
box.rotation.y = time * 0.5;
sphere.position.y = 0.5 + Math.sin(time) * 0.2;
cylinder.rotation.x = time * 0.3;
});
return scene;
},
// 更新场景信息
updateSceneInfo() {
if (this.scene) {
this.objectCount = this.scene.meshes.length;
}
},
// 窗口大小变化处理
onWindowResize() {
if (this.engine) {
this.engine.resize();
}
},
},
};
</script>
<style scoped>
.babylon-container {
position: relative;
width: 100%;
height: 100%;
}
.canvas-container {
width: 100%;
height: 100%;
overflow: hidden;
}
.render-canvas {
width: 100%;
height: 100%;
display: block;
outline: none;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.loader {
color: white;
font-size: 18px;
}
.scene-info {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.6);
color: white;
padding: 10px 15px;
border-radius: 5px;
font-size: 14px;
}
.scene-info p {
margin: 5px 0;
}
</style>
(3)运行效果如下:

附:添加坐标系辅助器
1,样例代码
下面代码在前面的基础上做个改进,在原点位置添加一个坐标系辅助器(X 轴为红色,Y 轴为绿色,Z 轴为蓝色),方便我们进行定位。
<template>
<div class="babylon-container">
<div ref="canvasContainer" class="canvas-container">
<canvas ref="renderCanvas" class="render-canvas"></canvas>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="loading-overlay">
<div class="loader">加载中...</div>
</div>
<!-- 场景信息 -->
<div class="scene-info">
<p>物体数量: {{ objectCount }}</p>
<p>FPS: {{ fps.toFixed(1) }}</p>
</div>
</div>
</template>
<script>
import * as BABYLON from 'babylonjs';
export default {
name: "BabylonScene",
data() {
return {
engine: null,
scene: null,
loading: true,
error: null,
objectCount: 0,
fps: 60,
};
},
mounted() {
this.initBabylon();
},
beforeDestroy() {
// 销毁组件时释放内存,防止内存泄漏
if (this.engine) {
this.engine.dispose();
}
window.removeEventListener("resize", this.onWindowResize);
},
methods: {
initBabylon() {
const canvas = this.$refs.renderCanvas;
// 1. 初始化渲染引擎
this.engine = new BABYLON.Engine(canvas, true,
{ preserveDrawingBuffer: true, stencil: true });
// 2. 创建场景
this.scene = this.createScene(this.engine, canvas);
// 3. 隐藏加载遮罩
this.loading = false;
// 4. 注册渲染循环
this.engine.runRenderLoop(() => {
this.scene.render();
this.fps = this.engine.getFps();
});
// 5. 监听窗口调整大小
window.addEventListener("resize", this.onWindowResize);
// 6. 初始化场景统计
this.updateSceneInfo();
// 7. 显示坐标系辅助器
this.showAxisHelper(this.scene);
},
createScene(engine, canvas) {
const scene = new BABYLON.Scene(engine);
// 设置背景颜色
scene.clearColor = BABYLON.Color3.FromHexString('#aaaaaa').toColor4();
// 添加摄像头 (ArcRotateCamera 允许用户绕着中心点旋转)
const camera = new BABYLON.ArcRotateCamera(
'camera',
-Math.PI / 2,
Math.PI / 3,
7,
BABYLON.Vector3.Zero(),
scene
);
camera.attachControl(canvas, true);
// 设置相机控制
camera.wheelPrecision = 50;
camera.lowerRadiusLimit = 2;
camera.upperRadiusLimit = 50;
// 添加灯光
const light1 = new BABYLON.HemisphericLight(
'light1',
new BABYLON.Vector3(1, 1, 0),
scene
);
const light2 = new BABYLON.DirectionalLight(
'light2',
new BABYLON.Vector3(0, -1, 1),
scene
);
light2.position = new BABYLON.Vector3(5, 10, 5)
light2.intensity = 0.3
// 添加阴影生成器(核心)
const shadowGenerator = new BABYLON.ShadowGenerator(1024, light2)
shadowGenerator.useBlurExponentialShadowMap = true
shadowGenerator.blurKernel = 32
// 添加地面
const ground = BABYLON.MeshBuilder.CreateGround(
'ground',
{ width: 5, height: 5 },
scene
);
const groundMaterial = new BABYLON.StandardMaterial('groundMaterial', scene);
groundMaterial.diffuseColor = new BABYLON.Color3(0.8, 0.8, 0.8);
ground.material = groundMaterial;
// 接收阴影
ground.receiveShadows = true
// 创建一个立方体
const box = BABYLON.MeshBuilder.CreateBox("box", { size: 1 }, scene);
box.position = new BABYLON.Vector3(-1.5, 0.75, 0);
// 给立方体上色
const material = new BABYLON.StandardMaterial("boxMat", scene);
material.diffuseColor = new BABYLON.Color3(0, 0.5, 1);
box.material = material;
// 创建一个球体
const sphere = BABYLON.MeshBuilder.CreateSphere(
'sphere',
{ diameter: 1 },
scene
);
sphere.position = new BABYLON.Vector3(0, 0.75, 0);
// 给球体上色
const sphereMaterial = new BABYLON.StandardMaterial('sphereMaterial', scene);
sphereMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.8, 0.2);
sphere.material = sphereMaterial;
// 创建一个圆柱体
const cylinder = BABYLON.MeshBuilder.CreateCylinder(
'cylinder',
{ height: 1, diameter: 1 },
scene
);
cylinder.position = new BABYLON.Vector3(1.5, 0.75, 0);
// 给圆柱体上色
const cylinderMaterial = new BABYLON.StandardMaterial('cylinderMaterial', scene);
cylinderMaterial.diffuseColor = new BABYLON.Color3(0.2, 0.2, 0.8);
cylinder.material = cylinderMaterial;
// 投射阴影
shadowGenerator.addShadowCaster(box)
shadowGenerator.addShadowCaster(sphere)
shadowGenerator.addShadowCaster(cylinder)
// 添加动画
scene.onBeforeRenderObservable.add(() => {
const time = Date.now() / 1000;
box.rotation.y = time * 0.5;
sphere.position.y = 0.5 + Math.sin(time) * 0.2;
cylinder.rotation.x = time * 0.3;
});
return scene;
},
// 添加坐标系辅助器
showAxisHelper(scene) {
// X轴 - 红色
const xAxis = BABYLON.MeshBuilder.CreateLines(
'xAxis',
{
points: [
BABYLON.Vector3.Zero(),
new BABYLON.Vector3(5, 0, 0)
]
},
scene
);
xAxis.color = new BABYLON.Color3(1, 0, 0);
// Y轴 - 绿色
const yAxis = BABYLON.MeshBuilder.CreateLines(
'yAxis',
{
points: [
BABYLON.Vector3.Zero(),
new BABYLON.Vector3(0, 5, 0)
]
},
scene
);
yAxis.color = new BABYLON.Color3(0, 1, 0);
// Z轴 - 蓝色
const zAxis = BABYLON.MeshBuilder.CreateLines(
'zAxis',
{
points: [
BABYLON.Vector3.Zero(),
new BABYLON.Vector3(0, 0, 5)
]
},
scene
);
zAxis.color = new BABYLON.Color3(0, 0, 1);
},
// 更新场景信息
updateSceneInfo() {
if (this.scene) {
this.objectCount = this.scene.meshes.length;
}
},
// 窗口大小变化处理
onWindowResize() {
if (this.engine) {
this.engine.resize();
}
},
},
};
</script>
<style scoped>
.babylon-container {
position: relative;
width: 100%;
height: 100%;
}
.canvas-container {
width: 100%;
height: 100%;
overflow: hidden;
}
.render-canvas {
width: 100%;
height: 100%;
display: block;
outline: none;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.loader {
color: white;
font-size: 18px;
}
.scene-info {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.6);
color: white;
padding: 10px 15px;
border-radius: 5px;
font-size: 14px;
}
.scene-info p {
margin: 5px 0;
}
</style>
2,运行效果
全部评论(0)