BabylonJS - 基本元素
Babylon.js - 基本元素
Section titled “Babylon.js - 基本元素”Babylon.js 提供了创建任何 3D 场景的基础构建模块。理解这些核心组件——Engine(引擎)、Scene(场景)、Camera(相机)、Lights(光源)和 Meshes(网格)——是构建交互式 3D Web 应用和游戏的第一步。
让我们逐步构建一个简单的场景,看看这些元素是如何协同工作的。
核心组件设置
Section titled “核心组件设置”步骤 1: HTML 结构和 Canvas
Section titled “步骤 1: HTML 结构和 Canvas”每个 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>步骤 2: Engine (引擎)
Section titled “步骤 2: Engine (引擎)”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 类和函数。步骤 3: Scene (场景)
Section titled “步骤 3: Scene (场景)”一个 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();步骤 4: Render Loop (渲染循环)
Section titled “步骤 4: Render Loop (渲染循环)”仅仅创建引擎和场景不足以显示任何东西。你需要告诉引擎持续渲染场景。这通过 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 (焦点), sceneconst camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 10, BABYLON.Vector3.Zero(), scene);
// 将相机附加到 canvas,启用用户输入 (鼠标/触摸)camera.attachControl(canvas, true);
// 创建一个基本光源// 参数: 名称, 方向 (向上向量), sceneconst light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// 调整光照强度 (可选)light.intensity = 0.7;步骤 6: 添加 Mesh (网格 / 形状)
Section titled “步骤 6: 添加 Mesh (网格 / 形状)”Meshes 是场景中可见的 3D 物体。Babylon.js 提供了 MeshBuilder 类,可以轻松创建各种标准形状。
// 在 createScene 函数内部 (相机和光源之后):
// 创建一个球体// 参数: 名称, 选项 (直径, 分段数等), sceneconst sphere = BABYLON.MeshBuilder.CreateSphere("sphere", { diameter: 2, segments: 32 }, scene);// 向上定位球体sphere.position.y = 1;
// 创建一个地面平面// 参数: 名称, 选项 (宽度, 高度, 细分数等), sceneconst ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 6, height: 6 }, scene);完整的基本场景代码
Section titled “完整的基本场景代码”<!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 形状
Section titled “常用 MeshBuilder 形状”这里是使用 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 (父子级关联)
Section titled “Parenting (父子级关联)”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;Parenting 示例
Section titled “Parenting 示例”这个示例展示了一个较小的盒子关联到一个较大的盒子。较大的盒子被缩放,子级会继承相对于其自身位置的缩放。
<!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>输出描述 (Parenting 示例)
Section titled “输出描述 (Parenting 示例)”这个示例展示了一个蓝色的、扁平的矩形盒子绕其垂直轴缓慢旋转。其侧面连接着一个较小的红色立方体,它随父级蓝色盒子一起旋转,保持其相对位置。
除了基本的背景颜色外,你还可以使用雾 (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());Ambient Color (环境光颜色)
Section titled “Ambient Color (环境光颜色)”scene.ambientColor 定义了一个全局的环境光颜色,它会影响材质(特别是 StandardMaterial 的 ambientColor 属性)。它提供了一个基础的光照级别,防止未被直射光触及的区域完全变黑。PBR 材质处理环境光的方式不同,通常通过环境纹理实现。
// 添加柔和的环境光scene.ambientColor = new BABYLON.Color3(0.1, 0.1, 0.1);Fog (雾)
Section titled “Fog (雾)”雾可以通过使远处的物体淡入特定颜色来增加深度和氛围。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 是大小环境示例描述
Section titled “环境示例描述”想象一下修改之前的基础场景。使用 scene.fogMode = BABYLON.Scene.FOGMODE_LINEAR 添加雾,并设置适当的开始/结束距离和颜色。然后,不使用 scene.clearColor,而是使用 scene.createDefaultSkybox 创建一个天空盒,并使用合适的 .env 环境纹理文件。球体和地面现在将显示在逼真的天空背景下,如果你使用了 PBR 材质,它们会逼真地反射环境。地面远处的部分将淡入雾的颜色。