Babylon.js 场景基础 #
核心概念 #
在 Babylon.js 中,场景(Scene)是所有 3D 对象的容器。理解引擎(Engine)和场景(Scene)的关系是学习 Babylon.js 的第一步。
text
┌─────────────────────────────────────────────────────────────┐
│ Babylon.js 架构层次 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Engine │ │
│ │ - 渲染引擎 │ │
│ │ - WebGL/WebGPU 上下文 │ │
│ │ - 渲染循环管理 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Scene │ │
│ │ - 3D 对象容器 │ │
│ │ - 相机、光源、网格 │ │
│ │ - 材质、纹理 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Camera │ │ Light │ │ Mesh │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
引擎(Engine) #
创建引擎 #
引擎是 Babylon.js 的核心,负责 WebGL/WebGPU 上下文管理和渲染循环。
javascript
const canvas = document.getElementById('renderCanvas');
// 基础创建
const engine = new BABYLON.Engine(canvas, true);
// 带配置创建
const engine = new BABYLON.Engine(canvas, true, {
preserveDrawingBuffer: true, // 保留绘制缓冲区(截图需要)
stencil: true, // 启用模板缓冲
antialias: true, // 抗锯齿
alpha: true, // 透明背景
powerPreference: 'high-performance'
});
引擎配置选项 #
text
┌─────────────────────────────────────────────────────────────┐
│ Engine 配置选项 │
├─────────────────────────────────────────────────────────────┤
│ │
│ preserveDrawingBuffer │
│ - 类型: boolean │
│ - 默认: false │
│ - 用途: 截图、后处理需要设为 true │
│ │
│ stencil │
│ - 类型: boolean │
│ - 默认: true │
│ - 用途: 阴影、遮罩效果 │
│ │
│ antialias │
│ - 类型: boolean │
│ - 默认: true │
│ - 用途: 边缘抗锯齿 │
│ │
│ alpha │
│ - 类型: boolean │
│ - 默认: false │
│ - 用途: 透明背景 │
│ │
│ powerPreference │
│ - 类型: 'default' | 'high-performance' | 'low-power' │
│ - 默认: 'default' │
│ - 用途: GPU 性能偏好 │
│ │
└─────────────────────────────────────────────────────────────┘
引擎常用方法 #
javascript
// 获取渲染尺寸
const width = engine.getRenderWidth();
const height = engine.getRenderHeight();
// 获取硬件缩放级别
const scale = engine.getHardwareScalingLevel();
// 设置硬件缩放(性能优化)
engine.setHardwareScalingLevel(0.5);
// 获取帧率
const fps = engine.getFps();
// 强制调整尺寸
engine.resize();
// 释放资源
engine.dispose();
场景(Scene) #
创建场景 #
javascript
// 基础创建
const scene = new BABYLON.Scene(engine);
// 带选项创建
const scene = new BABYLON.Scene(engine, {
useRightHandedSystem: false, // 坐标系
autoClear: true // 自动清除
});
场景基本属性 #
javascript
// 背景颜色
scene.clearColor = new BABYLON.Color4(0.1, 0.1, 0.2, 1);
// 环境颜色
scene.ambientColor = new BABYLON.Color3(0.3, 0.3, 0.3);
// 雾效果
scene.fogMode = BABYLON.Scene.FOGMODE_EXP2;
scene.fogDensity = 0.01;
scene.fogColor = new BABYLON.Color3(0.9, 0.9, 0.85);
// 背面剔除
scene.backFaceCulling = false;
// 深度预处理
scene.useDepthPrePass = true;
坐标系 #
text
┌─────────────────────────────────────────────────────────────┐
│ Babylon.js 坐标系 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 默认左手坐标系: │
│ │
│ Y (上) │
│ │ │
│ │ │
│ │ │
│ └───────── X (右) │
│ / │
│ / │
│ Z (前) │
│ │
│ 切换右手坐标系: │
│ scene.useRightHandedSystem = true; │
│ │
└─────────────────────────────────────────────────────────────┘
Vector3 向量 #
javascript
// 创建向量
const v1 = new BABYLON.Vector3(1, 2, 3);
const v2 = BABYLON.Vector3.Zero();
const v3 = BABYLON.Vector3.One();
const v4 = BABYLON.Vector3.Up();
const v5 = BABYLON.Vector3.Forward();
// 向量运算
const sum = v1.add(v2);
const diff = v1.subtract(v2);
const scaled = v1.scale(2);
const distance = BABYLON.Vector3.Distance(v1, v2);
const normalized = v1.normalize();
// 向量属性
const length = v1.length();
const lengthSq = v1.lengthSquared();
渲染循环 #
基本渲染循环 #
javascript
// 启动渲染循环
engine.runRenderLoop(function() {
scene.render();
});
// 使用箭头函数
engine.runRenderLoop(() => {
scene.render();
});
多场景渲染 #
javascript
const scene1 = new BABYLON.Scene(engine);
const scene2 = new BABYLON.Scene(engine);
engine.runRenderLoop(() => {
scene1.render();
scene2.render();
});
停止渲染循环 #
javascript
// 停止所有渲染循环
engine.stopRenderLoop();
// 使用标志控制
let isRunning = true;
engine.runRenderLoop(() => {
if (isRunning) {
scene.render();
}
});
// 暂停
isRunning = false;
// 恢复
isRunning = true;
场景生命周期 #
初始化顺序 #
text
┌─────────────────────────────────────────────────────────────┐
│ 场景初始化顺序 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 创建 Engine │
│ const engine = new BABYLON.Engine(canvas, true); │
│ │
│ 2. 创建 Scene │
│ const scene = new BABYLON.Scene(engine); │
│ │
│ 3. 创建 Camera │
│ const camera = new BABYLON.ArcRotateCamera(...); │
│ │
│ 4. 创建 Light │
│ const light = new BABYLON.HemisphericLight(...); │
│ │
│ 5. 创建 Mesh │
│ const box = BABYLON.MeshBuilder.CreateBox(...); │
│ │
│ 6. 启动渲染循环 │
│ engine.runRenderLoop(() => scene.render()); │
│ │
└─────────────────────────────────────────────────────────────┘
完整示例 #
javascript
const canvas = document.getElementById('renderCanvas');
const engine = new BABYLON.Engine(canvas, true);
const createScene = function() {
const scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color4(0.1, 0.1, 0.2, 1);
const camera = new BABYLON.ArcRotateCamera(
'camera',
Math.PI / 2,
Math.PI / 2,
5,
BABYLON.Vector3.Zero(),
scene
);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight(
'light',
new BABYLON.Vector3(1, 1, 0),
scene
);
const box = BABYLON.MeshBuilder.CreateBox('box', { size: 1 }, scene);
return scene;
};
const scene = createScene();
engine.runRenderLoop(function() {
scene.render();
});
window.addEventListener('resize', function() {
engine.resize();
});
场景管理 #
获取场景对象 #
javascript
// 获取所有网格
const meshes = scene.meshes;
// 获取所有相机
const cameras = scene.cameras;
// 获取所有光源
const lights = scene.lights;
// 获取所有材质
const materials = scene.materials;
// 按名称获取
const box = scene.getMeshByName('box');
const camera = scene.getCameraByName('camera');
const light = scene.getLightByName('light');
// 按 ID 获取
const mesh = scene.getMeshById('mesh-1');
添加和移除对象 #
javascript
// 网格已自动添加到场景
const box = BABYLON.MeshBuilder.CreateBox('box', {}, scene);
// 手动添加
scene.addMesh(box);
// 移除网格
scene.removeMesh(box);
// 销毁网格
box.dispose();
// 清空场景
scene.clearColor = new BABYLON.Color4(0, 0, 0, 1);
场景事件 #
javascript
// 渲染前事件
scene.onBeforeRenderObservable.add(() => {
// 每帧渲染前执行
});
// 渲染后事件
scene.onAfterRenderObservable.add(() => {
// 每帧渲染后执行
});
// 相机渲染前
scene.onBeforeCameraRenderObservable.add((camera) => {
// 相机渲染前
});
// 相机渲染后
scene.onAfterCameraRenderObservable.add((camera) => {
// 相机渲染后
});
场景优化 #
自动优化 #
javascript
// 自动优化场景
scene.autoClear = false; // 禁用自动清除
scene.autoClearDepthAndStencil = false;
// 自动批量处理
scene.autoAnimate = true;
// 禁用不必要的功能
scene.blockfreeActiveMeshesAndRenderingGroups = true;
手动优化 #
javascript
// 冻结材质
material.freeze();
// 冻结网格
box.freezeWorldMatrix();
// 解冻
box.unfreezeWorldMatrix();
// 批量冻结
scene.freezeActiveMeshes();
LOD(细节层次) #
javascript
// 创建 LOD
const box = BABYLON.MeshBuilder.CreateBox('box', { size: 2 }, scene);
// 添加 LOD 层级
const lod1 = BABYLON.MeshBuilder.CreateBox('lod1', { size: 1.8 }, scene);
const lod2 = BABYLON.MeshBuilder.CreateBox('lod2', { size: 1.5 }, scene);
box.addLODLevel(10, lod1);
box.addLODLevel(20, lod2);
box.addLODLevel(30, null); // 超过距离不渲染
场景拾取 #
射线拾取 #
javascript
// 点击拾取
scene.onPointerDown = function(evt, pickResult) {
if (pickResult.hit) {
console.log('点击了:', pickResult.pickedMesh.name);
console.log('点击位置:', pickResult.pickedPoint);
}
};
// 手动射线检测
const ray = scene.createPickingRay(
scene.pointerX,
scene.pointerY,
BABYLON.Matrix.Identity(),
camera
);
const hit = scene.pickWithRay(ray);
if (hit.hit) {
console.log('射线命中:', hit.pickedMesh.name);
}
拾取信息 #
javascript
scene.onPointerDown = function(evt, pickResult) {
if (pickResult.hit) {
// 命中的网格
const mesh = pickResult.pickedMesh;
// 命中点世界坐标
const point = pickResult.pickedPoint;
// 命中点法线
const normal = pickResult.getNormal();
// 命中距离
const distance = pickResult.distance;
// 命中面的索引
const faceId = pickResult.faceId;
// UV 坐标
const uv = pickResult.getTextureCoordinates();
}
};
场景调试 #
Inspector #
javascript
// 显示调试面板
scene.debugLayer.show();
// 带选项显示
scene.debugLayer.show({
overlay: true,
showExplorer: true,
showInspector: true,
embedMode: true
});
// 隐藏调试面板
scene.debugLayer.hide();
// 切换显示
if (scene.debugLayer.isVisible()) {
scene.debugLayer.hide();
} else {
scene.debugLayer.show();
}
性能监控 #
javascript
// 显示性能统计
scene.debugLayer.show();
// 获取性能数据
const fps = engine.getFps();
const drawCalls = scene.getActiveMeshes().length;
// 性能分析
scene.instrumentation = new BABYLON.SceneInstrumentation(scene);
console.log('绘制调用:', scene.instrumentation.drawCallsCounter.current);
场景序列化 #
导出场景 #
javascript
// 导出为 JSON
const serializedScene = BABYLON.SceneSerializer.Serialize(scene);
const json = JSON.stringify(serializedScene);
// 下载场景文件
function downloadScene(scene, filename) {
const serialized = BABYLON.SceneSerializer.Serialize(scene);
const json = JSON.stringify(serialized);
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename || 'scene.babylon';
a.click();
URL.revokeObjectURL(url);
}
导入场景 #
javascript
// 加载 .babylon 文件
BABYLON.SceneLoader.Load(
'/scenes/',
'scene.babylon',
engine,
function(scene) {
scene.createDefaultCameraOrLight(true, true, true);
scene.createDefaultEnvironment();
engine.runRenderLoop(() => {
scene.render();
});
}
);
实战:创建完整场景 #
javascript
const canvas = document.getElementById('renderCanvas');
const engine = new BABYLON.Engine(canvas, true);
const createScene = function() {
const scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color4(0.1, 0.1, 0.15, 1);
// 创建相机
const camera = new BABYLON.ArcRotateCamera(
'camera',
Math.PI / 4,
Math.PI / 3,
10,
BABYLON.Vector3.Zero(),
scene
);
camera.attachControl(canvas, true);
camera.lowerRadiusLimit = 3;
camera.upperRadiusLimit = 20;
// 创建光源
const light = new BABYLON.HemisphericLight(
'hemiLight',
new BABYLON.Vector3(0, 1, 0),
scene
);
light.intensity = 0.7;
const pointLight = new BABYLON.PointLight(
'pointLight',
new BABYLON.Vector3(2, 3, 2),
scene
);
pointLight.intensity = 0.5;
// 创建地面
const ground = BABYLON.MeshBuilder.CreateGround(
'ground',
{ width: 10, height: 10 },
scene
);
const groundMat = new BABYLON.StandardMaterial('groundMat', scene);
groundMat.diffuseColor = new BABYLON.Color3(0.3, 0.3, 0.35);
ground.material = groundMat;
// 创建多个物体
const box = BABYLON.MeshBuilder.CreateBox('box', { size: 1 }, scene);
box.position = new BABYLON.Vector3(-2, 0.5, 0);
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', { diameter: 1 }, scene);
sphere.position = new BABYLON.Vector3(0, 0.5, 0);
const cylinder = BABYLON.MeshBuilder.CreateCylinder('cylinder', { height: 1, diameter: 0.8 }, scene);
cylinder.position = new BABYLON.Vector3(2, 0.5, 0);
// 材质
const redMat = new BABYLON.StandardMaterial('redMat', scene);
redMat.diffuseColor = new BABYLON.Color3(1, 0.2, 0.2);
box.material = redMat;
const greenMat = new BABYLON.StandardMaterial('greenMat', scene);
greenMat.diffuseColor = new BABYLON.Color3(0.2, 1, 0.2);
sphere.material = greenMat;
const blueMat = new BABYLON.StandardMaterial('blueMat', scene);
blueMat.diffuseColor = new BABYLON.Color3(0.2, 0.2, 1);
cylinder.material = blueMat;
// 点击交互
scene.onPointerDown = function(evt, pickResult) {
if (pickResult.hit && pickResult.pickedMesh) {
const mesh = pickResult.pickedMesh;
mesh.scaling = mesh.scaling.scale(1.1);
}
};
// 动画
scene.onBeforeRenderObservable.add(() => {
box.rotation.y += 0.01;
sphere.position.y = 0.5 + Math.sin(Date.now() * 0.002) * 0.2;
cylinder.rotation.x += 0.01;
});
return scene;
};
const scene = createScene();
engine.runRenderLoop(() => {
scene.render();
});
window.addEventListener('resize', () => {
engine.resize();
});
下一步 #
现在你已经掌握了场景的基础知识,接下来学习 相机系统,了解如何控制视角和交互!
最后更新:2026-03-29