Skip to content

BabylonJS - 基本元素

Babylon.js 提供了创建任何 3D 场景的基础构建模块。理解这些核心组件——Engine(引擎)、Scene(场景)、Camera(相机)、Lights(光源)和 Meshes(网格)——是构建交互式 3D Web 应用和游戏的第一步。

让我们逐步构建一个简单的场景,看看这些元素是如何协同工作的。

每个 Babylon.js 应用都需要一个 HTML 文件。在该文件中,你需要一个 <canvas> 元素,它是 Babylon.js 渲染 3D 场景的绘图表面。你还需要包含 Babylon.js 库,通常通过 CDN 链接引入,或者如果你使用 NPM/Yarn,则从项目的 node_modules 中引入。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Babylon.js Basic Scene</title>
<!-- 包含 Babylon.js 核心库 -->
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<style>
html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; }
#renderCanvas { width: 100%; height: 100%; touch-action: none; /* 推荐用于指针事件 */ }
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<!-- 你的 JavaScript 代码将在这里 -->
<script type="text/javascript">
// Babylon.js 代码将在接下来的步骤中添加
</script>
</body>
</html>

Engine 是 Babylon.js 中的核心协调者。它负责与浏览器的渲染能力 (WebGL/WebGPU) 通信,并将场景绘制到 canvas 上。通过将 canvas 元素传递给 Engine 的构造函数来创建一个 Engine 实例。

// 获取 canvas 元素
const canvas = document.getElementById("renderCanvas");
// 创建 Babylon.js 引擎
const engine = new BABYLON.Engine(canvas, true); // true 启用抗锯齿
// BABYLON 对象包含所有核心 Babylon.js 类和函数。

一个 Scene 作为一个容器,容纳你想要渲染的一切:网格 (meshes)、光源 (lights)、相机 (cameras)、材质 (materials) 等。你需要创建一个场景并将其与引擎关联。

// 创建一个函数来封装场景创建
const createScene = function () {
// 创建新场景
const scene = new BABYLON.Scene(engine);
// 设置背景颜色 (可选)
scene.clearColor = new BABYLON.Color4(0.1, 0.1, 0.2, 1.0); // 深蓝色背景
// --- 我们稍后将在这里添加相机、光源和网格 ---
return scene;
};
// 调用 createScene 函数
const scene = createScene();

仅仅创建引擎和场景不足以显示任何东西。你需要告诉引擎持续渲染场景。这通过 engine.runRenderLoop 实现。这个函数接受一个回调函数,该回调函数会重复执行(理想情况下每秒 60 次),在该回调函数内部,你需要调用 scene.render()。

// 注册一个渲染循环来重复渲染场景
engine.runRenderLoop(function () {
scene.render();
});
// 处理浏览器窗口大小调整
window.addEventListener("resize", function () {
engine.resize();
});

此时,如果你运行 HTML 文件,你会看到一个空白的 canvas,带有我们设置的深蓝色背景。我们还没有向场景中添加任何东西。

步骤 5: 添加 Camera (相机) 和 Light (光源)

Section titled “步骤 5: 添加 Camera (相机) 和 Light (光源)”

在 3D 世界中,没有相机来查看它,没有光源来照亮它,你什么也看不到。让我们添加一个简单的相机和光源。

ArcRotateCamera 非常适合初学者。它围绕一个目标点轨道旋转,并且可以用鼠标或触摸轻松控制。

HemisphericLight 提供基础的环境光照,模拟来自天空的光线。

// 在 createScene 函数内部:
// 创建一个 ArcRotateCamera
// 参数: 名称, alpha (绕 Y 轴旋转), beta (绕 X 轴旋转), radius (距离), target (焦点), scene
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 10, BABYLON.Vector3.Zero(), scene);
// 将相机附加到 canvas,启用用户输入 (鼠标/触摸)
camera.attachControl(canvas, true);
// 创建一个基本光源
// 参数: 名称, 方向 (向上向量), scene
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// 调整光照强度 (可选)
light.intensity = 0.7;

Meshes 是场景中可见的 3D 物体。Babylon.js 提供了 MeshBuilder 类,可以轻松创建各种标准形状。

// 在 createScene 函数内部 (相机和光源之后):
// 创建一个球体
// 参数: 名称, 选项 (直径, 分段数等), scene
const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2, segments: 32 }, scene);
// 向上定位球体
sphere.position.y = 1;
// 创建一个地面平面
// 参数: 名称, 选项 (宽度, 高度, 细分数等), scene
const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 6, height: 6 }, scene);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Babylon.js Basic Scene</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<style>
html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; }
#renderCanvas { width: 100%; height: 100%; touch-action: none; }
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<script type="text/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.0);
const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 10, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.7;
const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2, segments: 32 }, scene);
sphere.position.y = 1;
const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 6, height: 6 }, scene);
return scene;
};
const scene = createScene();
engine.runRenderLoop(function () {
scene.render();
});
window.addEventListener("resize", function () {
engine.resize();
});
</script>
</body>
</html>

运行这段代码将显示一个 3D 场景,其中包含一个白色球体放置在白色地面平面上,在深蓝色背景下被环境光照亮。你可以点击并拖动鼠标来围绕球体旋转视图,并使用鼠标滚轮(或捏合手势)进行放大和缩小。

这里是使用 MeshBuilder 创建一些常用形状的快速参考:

形状语法示例
盒子 (Box)BABYLON.MeshBuilder.CreateBox(“box”, { size: 2 }, scene);
球体 (Sphere)BABYLON.MeshBuilder.CreateSphere(“sphere”, { diameter: 2, segments: 32 }, scene);
平面 (Plane)BABYLON.MeshBuilder.CreatePlane(“plane”, { width: 5, height: 5 }, scene);
地面 (Ground)BABYLON.MeshBuilder.CreateGround(“ground”, { width: 10, height: 10 }, scene);
圆柱体 (Cylinder)BABYLON.MeshBuilder.CreateCylinder(“cylinder”, { height: 3, diameterTop: 1, diameterBottom: 1.5, tessellation: 24 }, scene);
圆环 (Torus)BABYLON.MeshBuilder.CreateTorus(“torus”, { diameter: 5, thickness: 1, tessellation: 32 }, scene);
扭结 (Knot)BABYLON.MeshBuilder.CreateTorusKnot(“knot”, { radius: 2, tube: 0.5, radialSegments: 128, tubularSegments: 64, p: 2, q: 3 }, scene);
线条 (Lines)const points = [ new BABYLON.Vector3(-5, 0, 0), new BABYLON.Vector3(5, 0, 0) ];
BABYLON.MeshBuilder.CreateLines(“lines”, { points: points }, scene);
高度图地面 (Ground From Height Map)BABYLON.MeshBuilder.CreateGroundFromHeightMap(“groundMap”, “url/to/heightMap.png”, { width: 100, height: 100, subdivisions: 50, minHeight: 0, maxHeight: 10 }, scene);

变换: Position (位置), Rotation (旋转), Scaling (缩放)

Section titled “变换: Position (位置), Rotation (旋转), Scaling (缩放)”

一旦你创建了一个网格,你通常会想要移动、旋转或调整它的大小。网格具有 position、rotation (或 rotationQuaternion) 和 scaling 属性,这些属性都是 Vector3 对象(rotationQuaternion 除外)。

  • Position: 改变网格在 3D 空间中的位置 (X, Y, Z 坐标)。使用 mesh.position = new BABYLON.Vector3(x, y, z); 或修改分量,例如 mesh.position.x += 1;。
  • Rotation: 绕 X、Y 和 Z 轴旋转网格。以弧度为单位度量。使用 mesh.rotation = new BABYLON.Vector3(radiansX, radiansY, radiansZ); 或 mesh.rotation.y += Math.PI / 4; (绕 Y 轴旋转 45 度)。对于复杂的旋转,通常首选使用四元数 (mesh.rotationQuaternion) 以避免万向节死锁 (gimbal lock)。
  • Scaling: 沿 X、Y 和 Z 轴调整网格的大小。值为 1 表示原始大小。使用 mesh.scaling = new BABYLON.Vector3(scaleX, scaleY, scaleZ); 例如,mesh.scaling = new BABYLON.Vector3(2, 1, 1); (宽度加倍)。
// 变换示例
const box = BABYLON.MeshBuilder.CreateBox("myBox", { size: 1 }, scene);
// 移动盒子
box.position = new BABYLON.Vector3(2, 0.5, 3);
// 绕 Y 轴旋转 45 度
box.rotation.y = Math.PI / 4;
// 让盒子宽度加倍
box.scaling.x = 2;

Parenting 允许你将网格以层级结构关联起来。当你变换父网格(移动、旋转、缩放)时,所有子网格都会相对于父网格进行变换。这对于创建复杂对象(如机器人:手臂关联到躯干,手关联到手臂)或太阳系(行星关联到太阳)非常有用。

// 创建父级盒子
const parentBox = BABYLON.MeshBuilder.CreateBox("parent", { size: 1 }, scene);
parentBox.position.x = -2;
// 创建子级球体
const childSphere = BABYLON.MeshBuilder.CreateSphere("child", { diameter: 0.5 }, scene);
// 设置父级
childSphere.parent = parentBox; // 指定父级
// 相对于父级原点定位子级
childSphere.position.y = 1; // 将球体放置在父级盒子中心上方 1 单位处
// 现在,如果你移动或旋转 parentBox,childSphere 会随之移动/旋转。
// parentBox.rotation.y = Math.PI / 2;

这个示例展示了一个较小的盒子关联到一个较大的盒子。较大的盒子被缩放,子级会继承相对于其自身位置的缩放。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Babylon.js - Parenting Demo</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
<style>
html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; }
#renderCanvas { width: 100%; height: 100%; touch-action: none; }
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<script type="text/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.2, 0.4, 0.2, 1.0); // 偏绿色的背景
const camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2.2, Math.PI / 3, 15, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 1.0;
// Parent Box (larger, scaled)
const boxParent = BABYLON.MeshBuilder.CreateBox("BoxParent", { size: 2.0 }, scene);
boxParent.position = new BABYLON.Vector3(0, 1, 0);
boxParent.scaling = new BABYLON.Vector3(1.5, 0.5, 1.0); // 缩放: 更宽, 更矮
// Child Box (smaller)
const boxChild = BABYLON.MeshBuilder.CreateBox("BoxChild", { size: 0.8 }, scene);
boxChild.parent = boxParent; // 指定父级
boxChild.position.x = 1.5; // 相对于父级中心定位
boxChild.position.y = 1.0; // 相对于父级中心定位
// 添加简单的材质以区分颜色
const parentMat = new BABYLON.StandardMaterial("parentMat", scene);
parentMat.diffuseColor = new BABYLON.Color3(0.5, 0.5, 1.0); // 蓝色
boxParent.material = parentMat;
const childMat = new BABYLON.StandardMaterial("childMat", scene);
childMat.diffuseColor = new BABYLON.Color3(1.0, 0.5, 0.5); // 红色
boxChild.material = childMat;
const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 10, height: 10 }, scene);
// 动画化父级旋转
scene.onBeforeRenderObservable.add(() => {
boxParent.rotation.y += 0.01;
});
return scene;
};
const scene = createScene();
engine.runRenderLoop(function () { scene.render(); });
window.addEventListener("resize", function () { engine.resize(); });
</script>
</body>
</html>

这个示例展示了一个蓝色的、扁平的矩形盒子绕其垂直轴缓慢旋转。其侧面连接着一个较小的红色立方体,它随父级蓝色盒子一起旋转,保持其相对位置。

除了基本的背景颜色外,你还可以使用雾 (fog)、环境光颜色 (ambient color) 以及天空盒 (skyboxes) 或环境纹理 (environment textures) 来控制场景的整体环境,以实现逼真的光照和背景效果。

如前所述,scene.clearColor 设置纯色背景。

// 设置背景为浅灰色
scene.clearColor = new BABYLON.Color4(0.8, 0.8, 0.8, 1.0);
// 或使用预定义颜色
scene.clearColor = BABYLON.Color4.FromColor3(BABYLON.Color3.Teal());

scene.ambientColor 定义了一个全局的环境光颜色,它会影响材质(特别是 StandardMaterial 的 ambientColor 属性)。它提供了一个基础的光照级别,防止未被直射光触及的区域完全变黑。PBR 材质处理环境光的方式不同,通常通过环境纹理实现。

// 添加柔和的环境光
scene.ambientColor = new BABYLON.Color3(0.1, 0.1, 0.1);

雾可以通过使远处的物体淡入特定颜色来增加深度和氛围。Babylon.js 支持几种雾模式:

  • BABYLON.Scene.FOGMODE_NONE: 无雾 (默认)。
  • BABYLON.Scene.FOGMODE_EXP: 雾的密度随距离呈指数增长。
  • BABYLON.Scene.FOGMODE_EXP2: 类似于 EXP,但密度增长更快。
  • BABYLON.Scene.FOGMODE_LINEAR: 雾在开始距离和结束距离之间线性增加。
// 启用线性雾
scene.fogMode = BABYLON.Scene.FOGMODE_LINEAR;
scene.fogColor = new BABYLON.Color3(0.9, 0.9, 0.85); // 雾的颜色 (例如,浅灰黄色)
scene.fogStart = 20.0; // 雾开始出现的距离
scene.fogEnd = 60.0; // 雾达到最大浓度时的距离
// 对于指数雾,使用 density 而非 start/end:
// scene.fogMode = BABYLON.Scene.FOGMODE_EXP;
// scene.fogDensity = 0.01;

Skybox (天空盒) 和 Environment Textures (环境纹理)

Section titled “Skybox (天空盒) 和 Environment Textures (环境纹理)”

Skybox 是一个环绕场景的大立方体,表面贴有天空或环境的图像纹理。这创造了一个逼真的背景。更重要的是,现代渲染(特别是 PBR)使用立方体纹理(通常是 .hdr 或 .env 文件,由 HDR 图像处理而来)作为 scene.environmentTexture。这个纹理既提供了背景,也为材质提供了逼真的基于图像的光照 (Image-Based Lighting - IBL) 和反射效果。

手动创建一个简单的天空盒:

// 创建一个用于天空盒的大盒子
const skybox = BABYLON.MeshBuilder.CreateBox("skyBox", { size: 1000.0 }, scene);
// 创建天空盒材质
const skyboxMaterial = new BABYLON.StandardMaterial("skyBoxMat", scene);
skyboxMaterial.backFaceCulling = false; // 从盒子内部看到纹理
// 加载一个立方体纹理 (需要 6 张图片: _px, _nx, _py, _ny, _pz, _nz)
// 或单个 .env 或 .dds 文件
skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("textures/skybox/skybox", scene);
skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
// 使天空盒不受场景光照影响
skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
skyboxMaterial.disableLighting = true;
// 应用材质
skybox.material = skyboxMaterial;
// 确保天空盒在所有其他物体后面
skybox.infiniteDistance = true;

使用环境纹理(现代方法,对 PBR 更好):

// 加载一个环境纹理 (例如,预过滤的 .env 文件)
const environmentTex = BABYLON.CubeTexture.CreateFromPrefilteredData("textures/environment.env", scene);
scene.environmentTexture = environmentTex;
// 可选: 根据环境纹理创建天空盒网格
scene.createDefaultSkybox(environmentTex, true, 1000); // true 表示使用该纹理作为天空盒,1000 是大小

想象一下修改之前的基础场景。使用 scene.fogMode = BABYLON.Scene.FOGMODE_LINEAR 添加雾,并设置适当的开始/结束距离和颜色。然后,不使用 scene.clearColor,而是使用 scene.createDefaultSkybox 创建一个天空盒,并使用合适的 .env 环境纹理文件。球体和地面现在将显示在逼真的天空背景下,如果你使用了 PBR 材质,它们会逼真地反射环境。地面远处的部分将淡入雾的颜色。