跳到主要内容

Babylon.js 知识点总结

Babylon.js 是一个强大的、功能丰富的、开源的 3D 引擎,能够渲染交互式 3D 和 2D 图形,使用 HTML5 和 WebGL。

核心概念

三大核心组件

Babylon.js 的核心由三个组件构成:

  1. Engine(引擎) - 渲染引擎,负责与 WebGL 交互
  2. Scene(场景) - 3D 世界的容器
  3. Camera(相机) - 定义观察者的视角
// 基本结构
const canvas = document.getElementById('renderCanvas');
const engine = new BABYLON.Engine(canvas, true);
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 5, -10), scene);

// 渲染循环
engine.runRenderLoop(() => {
scene.render();
});

Engine(引擎)

引擎是 Babylon.js 的核心,负责初始化 WebGL 上下文和管理渲染循环。

// 创建引擎
const engine = new BABYLON.Engine(canvas, antialias, options, adaptToDeviceRatio);

// 引擎选项
const engine = new BABYLON.Engine(canvas, true, {
preserveDrawingBuffer: true,
stencil: true,
antialias: true,
alpha: false,
premultipliedAlpha: false,
powerPreference: "high-performance"
});

// 适配设备像素比
engine.setHardwareScalingLevel(1 / window.devicePixelRatio);

// 渲染循环
engine.runRenderLoop(() => {
scene.render();
});

// 响应式处理
window.addEventListener('resize', () => {
engine.resize();
});

引擎特性

  • WebGL 1.0 和 2.0 支持
  • WebGPU 支持(实验性)
  • 自动降级:WebGL 2.0 → WebGL 1.0 → 2D Canvas
  • 多场景支持:一个引擎可以渲染多个场景

Scene(场景)

场景是所有对象的容器,管理渲染、动画和事件。

const scene = new BABYLON.Scene(engine);

// 设置背景色
scene.clearColor = new BABYLON.Color3(0.1, 0.1, 0.1);

// 设置环境色
scene.ambientColor = new BABYLON.Color3(0.3, 0.3, 0.3);

// 启用雾效果
scene.fogMode = BABYLON.Scene.FOGMODE_EXP;
scene.fogDensity = 0.01;
scene.fogColor = new BABYLON.Color3(0.9, 0.9, 0.85);

// 启用阴影
scene.shadowsEnabled = true;

// 启用物理引擎
const gravityVector = new BABYLON.Vector3(0, -9.81, 0);
const physicsPlugin = new BABYLON.CannonJSPlugin();
scene.enablePhysics(gravityVector, physicsPlugin);

场景属性

  • clearColor: 场景背景色
  • ambientColor: 环境光颜色
  • fogMode: 雾模式(NONE/EXP/EXP2/LINEAR)
  • shadowsEnabled: 是否启用阴影
  • lightsEnabled: 是否启用光照
  • texturesEnabled: 是否启用纹理

Camera(相机)

FreeCamera(自由相机)

可以自由移动和旋转的相机。

const camera = new BABYLON.FreeCamera('camera1', 
new BABYLON.Vector3(0, 5, -10),
scene
);

camera.setTarget(BABYLON.Vector3.Zero());
camera.attachControls(canvas, true);

ArcRotateCamera(弧形旋转相机)

围绕目标点旋转的相机,适合查看对象。

const camera = new BABYLON.ArcRotateCamera(
'camera1',
-Math.PI / 2, // alpha(水平角度)
Math.PI / 2.5, // beta(垂直角度)
10, // radius(距离)
BABYLON.Vector3.Zero(), // target(目标点)
scene
);

camera.attachControls(canvas, true);

UniversalCamera(通用相机)

支持触摸和游戏手柄的相机。

const camera = new BABYLON.UniversalCamera('camera1', 
new BABYLON.Vector3(0, 0, -10),
scene
);
camera.attachControls(canvas, true);

FollowCamera(跟随相机)

跟随目标的相机。

const camera = new BABYLON.FollowCamera('camera1', 
new BABYLON.Vector3(0, 10, -10),
scene
);
camera.lockedTarget = mesh;
camera.radius = 10;
camera.heightOffset = 5;

相机控制

// 使用 ArcRotateCamera 的控制器
camera.attachControls(canvas, true);

// 禁用控制
camera.detachControls();

// 设置相机限制
camera.lowerBetaLimit = 0.1;
camera.upperBetaLimit = Math.PI / 2.2;
camera.lowerRadiusLimit = 5;
camera.upperRadiusLimit = 20;

Mesh(网格)

内置网格

// 立方体
const box = BABYLON.MeshBuilder.CreateBox('box', {
size: 2,
width: 1,
height: 1,
depth: 1
}, scene);

// 球体
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {
diameter: 2,
segments: 32
}, scene);

// 平面
const plane = BABYLON.MeshBuilder.CreatePlane('plane', {
size: 2,
width: 1,
height: 1
}, scene);

// 圆柱体
const cylinder = BABYLON.MeshBuilder.CreateCylinder('cylinder', {
diameter: 2,
height: 3,
tessellation: 32
}, scene);

// 圆环
const torus = BABYLON.MeshBuilder.CreateTorus('torus', {
diameter: 2,
thickness: 0.5,
tessellation: 32
}, scene);

// 地面
const ground = BABYLON.MeshBuilder.CreateGround('ground', {
width: 10,
height: 10,
subdivisions: 2
}, scene);

自定义网格

// 使用顶点创建自定义网格
const customMesh = new BABYLON.Mesh('custom', scene);

const positions = [
-1, -1, 0,
1, -1, 0,
0, 1, 0
];

const indices = [0, 1, 2];

const vertexData = new BABYLON.VertexData();
vertexData.positions = positions;
vertexData.indices = indices;
vertexData.normals = [];
BABYLON.VertexData.ComputeNormals(positions, indices, vertexData.normals);

vertexData.applyToMesh(customMesh);

网格操作

// 位置
mesh.position = new BABYLON.Vector3(1, 2, 3);
mesh.position.x = 1;

// 旋转(弧度制)
mesh.rotation = new BABYLON.Vector3(0, Math.PI / 4, 0);
mesh.rotationQuaternion = new BABYLON.Quaternion();

// 缩放
mesh.scaling = new BABYLON.Vector3(2, 2, 2);

// 父级关系
mesh.setParent(parentMesh);

// 克隆
const clonedMesh = mesh.clone('clonedMesh');

// 合并网格
const mergedMesh = BABYLON.Mesh.MergeMeshes([mesh1, mesh2], true, true);

Material(材质)

StandardMaterial(标准材质)

PBR 标准材质,支持物理渲染。

const material = new BABYLON.StandardMaterial('material', scene);

material.diffuseColor = new BABYLON.Color3(1, 0, 0); // 漫反射颜色
material.specularColor = new BABYLON.Color3(1, 1, 1); // 高光颜色
material.emissiveColor = new BABYLON.Color3(0, 0, 0); // 自发光颜色
material.ambientColor = new BABYLON.Color3(0.2, 0.2, 0.2); // 环境色

material.roughness = 0.5; // 粗糙度
material.metallic = 0.5; // 金属度
material.metallicF0Factor = 0.5; // 金属 F0 因子

material.alpha = 1.0; // 透明度
material.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE;

material.backFaceCulling = true; // 背面剔除
material.twoSidedLighting = false; // 双面光照
material.wireframe = false; // 线框模式

PBRMaterial(PBR 材质)

更高级的物理渲染材质。

const pbr = new BABYLON.PBRMaterial('pbr', scene);

pbr.baseColor = new BABYLON.Color3(1, 0, 0);
pbr.metallic = 0.9;
pbr.roughness = 0.1;

// 纹理
pbr.baseTexture = new BABYLON.Texture('diffuse.jpg', scene);
pbr.normalTexture = new BABYLON.Texture('normal.jpg', scene);
pbr.metallicRoughnessTexture = new BABYLON.Texture('metallicRoughness.jpg', scene);
pbr.occlusionTexture = new BABYLON.Texture('ao.jpg', scene);
pbr.emissiveTexture = new BABYLON.Texture('emissive.jpg', scene);

// 环境贴图
pbr.environmentTexture = hdrTexture;

材质类型

// MeshBasicMaterial - 不受光照影响
const basicMaterial = new BABYLON.StandardMaterial('basic', scene);
basicMaterial.disableLighting = true;

// MeshPhongMaterial - 高光材质
const phongMaterial = new BABYLON.StandardMaterial('phong', scene);
phongMaterial.specularPower = 32;

// MeshLambertMaterial - 漫反射材质
const lambertMaterial = new BABYLON.StandardMaterial('lambert', scene);
lambertMaterial.specularColor = BABYLON.Color3.Black();

// ShaderMaterial - 自定义着色器
const shaderMaterial = new BABYLON.ShaderMaterial('shader', scene, {
vertex: 'custom',
fragment: 'custom'
}, {
attributes: ['position', 'normal', 'uv'],
uniforms: ['worldViewProjection']
});

纹理

// 加载纹理
const texture = new BABYLON.Texture('path/to/texture.jpg', scene);

// 纹理设置
texture.uScale = 2; // U 方向缩放
texture.vScale = 2; // V 方向缩放
texture.uOffset = 0.5; // U 方向偏移
texture.vOffset = 0.5; // V 方向偏移
texture.uAng = Math.PI / 4; // U 方向旋转
texture.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE; // 重复模式
texture.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;

// 立方体贴图
const cubeTexture = new BABYLON.CubeTexture('path/to/env', scene, null, false, null, null, '.jpg', null, true);
scene.environmentTexture = cubeTexture;

// HDR 环境贴图
const hdrTexture = BABYLON.CubeTexture.CreateFromPrefilteredData('environment.dds', scene);
scene.environmentTexture = hdrTexture;

Light(光照)

光源类型

// 方向光 - 平行光(如太阳光)
const directionalLight = new BABYLON.DirectionalLight('light1',
new BABYLON.Vector3(0, -1, 0),
scene
);
directionalLight.diffuse = new BABYLON.Color3(1, 1, 1);
directionalLight.specular = new BABYLON.Color3(1, 1, 1);
directionalLight.intensity = 1.0;

// 点光源 - 从一点向四周发射
const pointLight = new BABYLON.PointLight('light2',
new BABYLON.Vector3(0, 10, 0),
scene
);
pointLight.diffuse = new BABYLON.Color3(1, 1, 1);
pointLight.range = 100;

// 聚光灯 - 圆锥形光束
const spotLight = new BABYLON.SpotLight('light3',
new BABYLON.Vector3(0, 10, 0),
new BABYLON.Vector3(0, -1, 0),
Math.PI / 4, // 角度
2, // 指数
scene
);
spotLight.diffuse = new BABYLON.Color3(1, 1, 1);
spotLight.range = 100;

// 半球光 - 模拟天空和地面
const hemisphericLight = new BABYLON.HemisphericLight('light4',
new BABYLON.Vector3(0, 1, 0),
scene
);
hemisphericLight.diffuse = new BABYLON.Color3(1, 1, 1);
hemisphericLight.groundColor = new BABYLON.Color3(0, 0, 0);
hemisphericLight.intensity = 0.7;

阴影

// 启用阴影
scene.shadowsEnabled = true;

// 创建阴影生成器
const shadowGenerator = new BABYLON.ShadowGenerator(1024, directionalLight);
shadowGenerator.useBlurExponentialShadowMap = true;
shadowGenerator.blurKernel = 32;

// 添加阴影投射者
shadowGenerator.addShadowCaster(mesh);

// 设置阴影接收者
ground.receiveShadows = true;

// 阴影类型
shadowGenerator.useBlurExponentialShadowMap = true; // 模糊指数阴影
shadowGenerator.usePercentageCloserFiltering = true; // PCF 阴影
shadowGenerator.useContactHardeningShadow = true; // 接触硬化阴影

Animation(动画)

使用 Animation

// 创建动画
const animationBox = new BABYLON.Animation(
'myAnimation',
'position.x',
30, // 帧率
BABYLON.Animation.ANIMATIONTYPE_FLOAT,
BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
);

// 定义关键帧
const keys = [];
keys.push({ frame: 0, value: 0 });
keys.push({ frame: 100, value: 5 });
keys.push({ frame: 200, value: 0 });
animationBox.setKeys(keys);

// 添加到网格
box.animations.push(animationBox);

// 开始动画
scene.beginAnimation(box, 0, 200, true);

使用 AnimationGroup

const animationGroup = new BABYLON.AnimationGroup('group');

// 创建多个动画
const anim1 = BABYLON.Animation.CreateAndStartAnimation(
'anim1',
mesh1,
'position.x',
30,
100,
0,
5,
BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
);

const anim2 = BABYLON.Animation.CreateAndStartAnimation(
'anim2',
mesh2,
'rotation.y',
30,
100,
0,
Math.PI * 2,
BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
);

animationGroup.addTargetedAnimation(anim1, mesh1);
animationGroup.addTargetedAnimation(anim2, mesh2);

animationGroup.play();

使用 AnimationPropertiesOverride

scene.animationPropertiesOverride = new BABYLON.AnimationPropertiesOverride();
scene.animationPropertiesOverride.enableBlending = true;
scene.animationPropertiesOverride.blendingSpeed = 0.1;

Loaders(加载器)

SceneLoader - 加载 3D 模型

// 加载 GLTF/GLB
BABYLON.SceneLoader.ImportMesh('', 'path/to/', 'model.gltf', scene, (meshes) => {
console.log('模型加载完成', meshes);
});

// 加载整个场景
BABYLON.SceneLoader.Append('', 'scene.babylon', scene, () => {
console.log('场景加载完成');
});

// 使用 AssetsManager 管理资源
const assetsManager = new BABYLON.AssetsManager(scene);

const meshTask = assetsManager.addMeshTask('task1', '', 'path/to/', 'model.babylon');
meshTask.onSuccess = (task) => {
console.log('加载成功', task.loadedMeshes);
};
meshTask.onError = (task, message, exception) => {
console.error('加载失败', message);
};

assetsManager.load();

支持的格式

  • .babylon - Babylon.js 原生格式
  • .gltf/.glb - GLTF 格式
  • .obj - OBJ 格式
  • .stl - STL 格式
  • .fbx - FBX 格式(需要插件)

物理引擎

使用 Cannon.js

// 启用物理引擎
const gravityVector = new BABYLON.Vector3(0, -9.81, 0);
const physicsPlugin = new BABYLON.CannonJSPlugin();
scene.enablePhysics(gravityVector, physicsPlugin);

// 添加物理体
const box = BABYLON.MeshBuilder.CreateBox('box', {}, scene);
box.physicsImpostor = new BABYLON.PhysicsImpostor(
box,
BABYLON.PhysicsImpostor.BoxImpostor,
{ mass: 1, restitution: 0.7 },
scene
);

// 物理体类型
BABYLON.PhysicsImpostor.BoxImpostor // 盒子
BABYLON.PhysicsImpostor.SphereImpostor // 球体
BABYLON.PhysicsImpostor.CylinderImpostor // 圆柱体
BABYLON.PhysicsImpostor.MeshImpostor // 网格
BABYLON.PhysicsImpostor.HeightmapImpostor // 高度图

使用 Ammo.js

const physicsPlugin = new BABYLON.AmmoJSPlugin();
scene.enablePhysics(gravityVector, physicsPlugin);

粒子系统

// 创建粒子系统
const particleSystem = new BABYLON.ParticleSystem('particles', 2000, scene);

// 设置发射器
particleSystem.emitter = mesh;
particleSystem.minEmitBox = new BABYLON.Vector3(-1, 0, -1);
particleSystem.maxEmitBox = new BABYLON.Vector3(1, 0, 1);

// 设置纹理
particleSystem.particleTexture = new BABYLON.Texture('path/to/flare.png', scene);

// 设置生命周期
particleSystem.minLifeTime = 0.5;
particleSystem.maxLifeTime = 1.5;

// 设置速度
particleSystem.minEmitPower = 1;
particleSystem.maxEmitPower = 3;
particleSystem.updateSpeed = 0.01;

// 设置颜色
particleSystem.color1 = new BABYLON.Color4(1, 1, 1, 1);
particleSystem.color2 = new BABYLON.Color4(1, 0, 0, 1);
particleSystem.colorDead = new BABYLON.Color4(0, 0, 0, 0);

// 设置大小
particleSystem.minSize = 0.1;
particleSystem.maxSize = 0.5;

// 设置方向
particleSystem.direction1 = new BABYLON.Vector3(-1, 1, -1);
particleSystem.direction2 = new BABYLON.Vector3(1, 1, 1);

// 开始发射
particleSystem.start();

后处理效果

// 创建后处理管道
const pipeline = new BABYLON.DefaultRenderingPipeline(
'defaultPipeline',
true,
scene,
[camera]
);

// 启用效果
pipeline.bloomEnabled = true;
pipeline.bloomKernel = 64;
pipeline.bloomScale = 0.5;
pipeline.bloomThreshold = 0.9;
pipeline.bloomWeight = 0.3;

pipeline.chromaticAberrationEnabled = true;
pipeline.chromaticAberration.aberrationAmount = 5;

pipeline.depthOfFieldEnabled = true;
pipeline.depthOfField.focusDistance = 100;

pipeline.fxaaEnabled = true; // 抗锯齿

// 自定义后处理
const postProcess = new BABYLON.PostProcess(
'custom',
'./shaders/custom',
['time'],
['textureSampler'],
1.0,
camera
);

scene.registerBeforeRender(() => {
postProcess.onApply = (effect) => {
effect.setFloat('time', scene.getEngine().getDeltaTime());
};
});

性能优化

实例化渲染

// 创建源网格
const sourceMesh = BABYLON.MeshBuilder.CreateBox('source', {}, scene);

// 创建实例
const instances = [];
for (let i = 0; i < 1000; i++) {
const instance = sourceMesh.createInstance('instance' + i);
instance.position.x = Math.random() * 20 - 10;
instance.position.y = Math.random() * 20 - 10;
instance.position.z = Math.random() * 20 - 10;
instances.push(instance);
}

LOD(细节层次)

const lod = new BABYLON.LOD('lod', scene);

// 添加不同细节级别的网格
lod.addMesh(highDetailMesh, 0);
lod.addMesh(mediumDetailMesh, 50);
lod.addMesh(lowDetailMesh, 100);

scene.addMesh(lod);

视锥体剔除

// 自动启用,但需要正确设置网格的包围盒
mesh.refreshBoundingInfo();

合并网格

// 合并多个网格
const mergedMesh = BABYLON.Mesh.MergeMeshes(
[mesh1, mesh2, mesh3],
true, // 合并材质
true, // 允许子网格
undefined,
false, // 不克隆源网格
true // 使用实例
);

性能监控

// 使用 SceneOptimizer
const optimizer = new BABYLON.SceneOptimizer(scene);
optimizer.optimize();

// 使用性能监控器
const perfMonitor = new BABYLON.PerfMonitor();
scene.onBeforeRenderObservable.add(() => {
perfMonitor.update();
console.log('FPS:', perfMonitor.fps);
});

常用工具和技巧

Picking(拾取)

// 鼠标拾取
scene.onPointerObservable.add((pointerInfo) => {
if (pointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
const pickResult = scene.pick(pointerInfo.event.offsetX, pointerInfo.event.offsetY);
if (pickResult.hit) {
console.log('点击了:', pickResult.pickedMesh);
}
}
});

// 射线拾取
const ray = scene.createPickingRay(
scene.pointerX,
scene.pointerY,
BABYLON.Matrix.Identity(),
camera
);
const hit = scene.pickWithRay(ray);

坐标转换

// 世界坐标转屏幕坐标
const vector = BABYLON.Vector3.Project(
mesh.position,
BABYLON.Matrix.Identity(),
scene.getTransformMatrix(),
camera.viewport.toGlobal(
engine.getRenderWidth(),
engine.getRenderHeight()
)
);

事件系统

// 观察者模式
mesh.onDisposeObservable.add(() => {
console.log('网格被释放');
});

scene.onBeforeRenderObservable.add(() => {
// 每帧执行
});

scene.onAfterRenderObservable.add(() => {
// 渲染后执行
});

工具函数

// 创建 GUI
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI('UI');
const button = BABYLON.GUI.Button.CreateSimpleButton('button', 'Click Me');
button.onPointerClickObservable.add(() => {
console.log('按钮被点击');
});
advancedTexture.addControl(button);

// 创建文本
const text = new BABYLON.GUI.TextBlock('text', 'Hello Babylon.js');
text.color = 'white';
text.fontSize = 24;
advancedTexture.addControl(text);

最佳实践

  1. 资源管理: 及时释放不需要的网格、材质和纹理

    mesh.dispose();
    material.dispose();
    texture.dispose();
  2. 使用对象池: 复用对象以减少垃圾回收

  3. 合理使用阴影: 阴影计算消耗大,只对必要对象启用

  4. 优化纹理大小: 使用合适的纹理分辨率

  5. 使用压缩纹理: 使用 KTX2/Basis 压缩格式

  6. 批处理: 合并相同材质的网格

  7. 使用 Web Workers: 将复杂计算移到 Worker 线程

  8. 性能监控: 使用 SceneOptimizer 和 PerfMonitor

与 Three.js 的对比

特性Babylon.jsThree.js
学习曲线较陡较平缓
功能丰富度更丰富基础功能完善
性能优秀优秀
物理引擎内置支持需要插件
后处理内置管道需要额外库
GUI 系统内置需要额外库
文档详细详细
社区活跃非常活跃

常用资源

版本说明

  • 5.0+: 使用 ES6 模块,需要构建工具
  • 4.x 及以下: 支持直接 script 标签引入
// 现代方式(推荐)
import * as BABYLON from '@babylonjs/core';
import '@babylonjs/loaders/glTF';

// 传统方式
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>