Babylon.js 网格几何体 #
网格概述 #
网格(Mesh)是 3D 场景中可见的物体,由顶点、边和面组成。Babylon.js 提供了丰富的网格创建和操作功能。
text
┌─────────────────────────────────────────────────────────────┐
│ 网格基本概念 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Vertex(顶点) │
│ - 3D 空间中的点 │
│ - 包含位置、法线、UV 等属性 │
│ │
│ Edge(边) │
│ - 连接两个顶点的线 │
│ │
│ Face(面) │
│ - 由边围成的区域 │
│ - 通常为三角形 │
│ │
│ Mesh = Vertices + Indices │
│ │
└─────────────────────────────────────────────────────────────┘
基础形状创建 #
立方体 #
javascript
// 基础立方体
const box = BABYLON.MeshBuilder.CreateBox('box', {}, scene);
// 自定义尺寸
const box = BABYLON.MeshBuilder.CreateBox('box', {
width: 2,
height: 1,
depth: 3
}, scene);
// 带圆角的立方体
const roundedBox = BABYLON.MeshBuilder.CreateBox('roundedBox', {
width: 2,
height: 2,
depth: 2,
sideOrientation: BABYLON.Mesh.DOUBLESIDE
}, scene);
球体 #
javascript
// 基础球体
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {}, scene);
// 自定义球体
const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', {
diameter: 2, // 直径
segments: 32, // 细分程度
diameterX: 2, // X 轴直径(可创建椭球)
diameterY: 1,
diameterZ: 2
}, scene);
圆柱体 #
javascript
// 基础圆柱
const cylinder = BABYLON.MeshBuilder.CreateCylinder('cylinder', {}, scene);
// 自定义圆柱
const cylinder = BABYLON.MeshBuilder.CreateCylinder('cylinder', {
height: 3,
diameterTop: 1, // 顶部直径
diameterBottom: 2, // 底部直径
tessellation: 32 // 细分程度
}, scene);
// 圆锥(顶部直径为 0)
const cone = BABYLON.MeshBuilder.CreateCylinder('cone', {
height: 2,
diameterTop: 0,
diameterBottom: 2
}, scene);
平面 #
javascript
// 基础平面
const plane = BABYLON.MeshBuilder.CreatePlane('plane', {}, scene);
// 自定义平面
const plane = BABYLON.MeshBuilder.CreatePlane('plane', {
width: 5,
height: 3,
sideOrientation: BABYLON.Mesh.DOUBLESIDE // 双面渲染
}, scene);
// 地面
const ground = BABYLON.MeshBuilder.CreateGround('ground', {
width: 10,
height: 10
}, scene);
// 带高度图的地面
const ground = BABYLON.MeshBuilder.CreateGroundFromHeightMap(
'ground',
'/textures/heightmap.jpg',
{
width: 100,
height: 100,
subdivisions: 50,
minHeight: 0,
maxHeight: 10
},
scene
);
圆环 #
javascript
// 圆环
const torus = BABYLON.MeshBuilder.CreateTorus('torus', {}, scene);
// 自定义圆环
const torus = BABYLON.MeshBuilder.CreateTorus('torus', {
diameter: 2, // 整体直径
thickness: 0.5, // 管道厚度
tessellation: 32 // 细分程度
}, scene);
其他形状 #
javascript
// 圆环结
const torusKnot = BABYLON.MeshBuilder.CreateTorusKnot('torusKnot', {}, scene);
// 多面体
const polyhedron = BABYLON.MeshBuilder.CreatePolyhedron('poly', {
type: 1, // 多面体类型
size: 1
}, scene);
// 胶囊体
const capsule = BABYLON.MeshBuilder.CreateCapsule('capsule', {
height: 2,
radius: 0.5
}, scene);
// 线条
const lines = BABYLON.MeshBuilder.CreateLines('lines', {
points: [
new BABYLON.Vector3(0, 0, 0),
new BABYLON.Vector3(1, 1, 0),
new BABYLON.Vector3(2, 0, 0)
]
}, scene);
// 虚线
const dashedLines = BABYLON.MeshBuilder.CreateDashedLines('dashed', {
points: [
new BABYLON.Vector3(0, 0, 0),
new BABYLON.Vector3(1, 1, 0),
new BABYLON.Vector3(2, 0, 0)
],
dashSize: 0.1,
gapSize: 0.1
}, scene);
网格变换 #
位置 #
javascript
// 设置位置
mesh.position = new BABYLON.Vector3(1, 2, 3);
// 单独设置
mesh.position.x = 1;
mesh.position.y = 2;
mesh.position.z = 3;
// 相对移动
mesh.position.addInPlace(new BABYLON.Vector3(1, 0, 0));
旋转 #
javascript
// 欧拉角旋转(弧度)
mesh.rotation = new BABYLON.Vector3(Math.PI / 4, Math.PI / 2, 0);
// 单独设置
mesh.rotation.x = Math.PI / 4;
mesh.rotation.y = Math.PI / 2;
mesh.rotation.z = 0;
// 四元数旋转
mesh.rotationQuaternion = new BABYLON.Quaternion(
0.707, 0, 0, 0.707
);
// 绕轴旋转
mesh.rotate(BABYLON.Axis.Y, Math.PI / 4, BABYLON.Space.LOCAL);
// 面向目标
mesh.lookAt(new BABYLON.Vector3(0, 0, 0));
缩放 #
javascript
// 设置缩放
mesh.scaling = new BABYLON.Vector3(2, 1, 1);
// 单独设置
mesh.scaling.x = 2;
mesh.scaling.y = 1;
mesh.scaling.z = 1;
// 均匀缩放
mesh.scaling = new BABYLON.Vector3(2, 2, 2);
// 或
mesh.scalingDeterminant = 2;
变换矩阵 #
javascript
// 获取世界矩阵
const worldMatrix = mesh.getWorldMatrix();
// 获取位置、旋转、缩放
const position = new BABYLON.Vector3();
const rotation = new BABYLON.Quaternion();
const scaling = new BABYLON.Vector3();
worldMatrix.decompose(scaling, rotation, position);
// 设置变换矩阵
const matrix = BABYLON.Matrix.Compose(
scaling,
rotation,
position
);
mesh.setPivotMatrix(matrix);
网格属性 #
基本属性 #
javascript
// 名称
mesh.name = 'myMesh';
// 可见性
mesh.isVisible = true;
// 启用/禁用
mesh.setEnabled(true);
// 渲染组
mesh.renderingGroupId = 0;
// 图层
mesh.layerMask = 0x0FFFFFFF;
边界信息 #
javascript
// 获取边界球
const boundingSphere = mesh.getBoundingInfo().boundingSphere;
const center = boundingSphere.centerWorld;
const radius = boundingSphere.radiusWorld;
// 获取边界盒
const boundingBox = mesh.getBoundingInfo().boundingBox;
const min = boundingBox.minimumWorld;
const max = boundingBox.maximumWorld;
// 计算边界
mesh.computeWorldMatrix(true);
mesh.refreshBoundingInfo();
几何信息 #
javascript
// 获取顶点数量
const vertexCount = mesh.getTotalVertices();
// 获取面数量
const faceCount = mesh.getTotalIndices() / 3;
// 获取顶点数据
const positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
const normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
const uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
const indices = mesh.getIndices();
网格操作 #
克隆 #
javascript
// 克隆网格
const clone = mesh.clone('clone');
// 深度克隆(包括子网格)
const deepClone = mesh.clone('deepClone', true);
实例化 #
javascript
// 创建实例(共享几何体,性能更好)
const instance = mesh.createInstance('instance');
// 实例可以有不同的位置、旋转、缩放
instance.position = new BABYLON.Vector3(2, 0, 0);
// 创建多个实例
for (let i = 0; i < 100; i++) {
const instance = mesh.createInstance('instance' + i);
instance.position = new BABYLON.Vector3(
Math.random() * 10,
Math.random() * 10,
Math.random() * 10
);
}
合并 #
javascript
// 合并多个网格
const merged = BABYLON.Mesh.MergeMeshes(
[mesh1, mesh2, mesh3],
true, // disposeSource
true, // allow32BitsIndices
undefined,
undefined,
true // subdivideWithSubMeshes
);
分离 #
javascript
// 分离网格
const subMeshes = mesh.subMeshes;
销毁 #
javascript
// 销毁网格
mesh.dispose();
// 销毁网格及其子对象
mesh.dispose(true);
模型加载 #
加载 glTF 模型 #
javascript
// 导入 glTF 模型
BABYLON.SceneLoader.ImportMesh(
'', // 空字符串表示加载所有网格
'/models/',
'model.glb',
scene,
function(meshes, particleSystems, skeletons) {
// 加载成功回调
console.log('加载了', meshes.length, '个网格');
// 设置模型位置
meshes[0].position = new BABYLON.Vector3(0, 0, 0);
// 播放骨骼动画
if (skeletons.length > 0) {
scene.beginAnimation(skeletons[0], 0, 100, true);
}
},
function(evt) {
// 加载进度回调
const loadedPercent = (evt.loaded * 100 / evt.total).toFixed(2);
console.log(`加载进度: ${loadedPercent}%`);
},
function(err) {
// 加载错误回调
console.error('加载失败:', err);
}
);
异步加载 #
javascript
// 使用 async/await
async function loadModel() {
const result = await BABYLON.SceneLoader.ImportMeshAsync(
'',
'/models/',
'model.glb',
scene
);
console.log('加载完成');
return result;
}
支持的格式 #
text
┌─────────────────────────────────────────────────────────────┐
│ 支持的模型格式 │
├─────────────────────────────────────────────────────────────┤
│ │
│ glTF/GLB ──────── 推荐,Web 3D 标准格式 │
│ - .gltf, .glb │
│ - 支持 PBR 材质、动画、骨骼 │
│ │
│ OBJ ───────────── 基础格式 │
│ - .obj │
│ - 简单几何,无动画 │
│ │
│ STL ───────────── 3D 打印格式 │
│ - .stl │
│ │
│ Babylon ───────── 原生格式 │
│ - .babylon │
│ │
│ 需要额外加载器: │
│ - FBX (需要转换) │
│ - Collada (.dae) │
│ │
└─────────────────────────────────────────────────────────────┘
加载器配置 #
javascript
// 加载 glTF 加载器
import '@babylonjs/loaders/glTF';
// 配置加载器
BABYLON.SceneLoader.OnPluginActivatedObservable.add(function(loader) {
if (loader.name === 'gltf') {
loader.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.ALL;
}
});
网格层级 #
父子关系 #
javascript
// 设置父级
childMesh.parent = parentMesh;
// 子网格会跟随父网格变换
parentMesh.position = new BABYLON.Vector3(5, 0, 0);
// childMesh 也会移动到相对位置
// 移除父级
childMesh.parent = null;
层级结构 #
text
┌─────────────────────────────────────────────────────────────┐
│ 网格层级示例 │
├─────────────────────────────────────────────────────────────┤
│ │
│ body (父级) │
│ / \ │
│ head arm (子级) │
│ / │
│ eye (孙级) │
│ │
│ 移动 body:所有子级一起移动 │
│ 移动 arm:只移动 arm 及其子级 │
│ 旋转 head:eye 跟随旋转 │
│ │
└─────────────────────────────────────────────────────────────┘
获取子对象 #
javascript
// 获取所有子对象
const children = mesh.getChildMeshes();
// 递归获取所有后代
const descendants = mesh.getChildMeshes(true);
// 按名称查找
const child = mesh.getChildMeshes().find(m => m.name === 'head');
网格拾取 #
射线检测 #
javascript
// 创建射线
const ray = new BABYLON.Ray(
camera.position,
camera.getForwardRay().direction,
100 // 最大距离
);
// 射线检测
const hit = scene.pickWithRay(ray, function(mesh) {
// 过滤函数
return mesh.name !== 'ground';
});
if (hit.hit) {
console.log('命中:', hit.pickedMesh.name);
console.log('命中点:', hit.pickedPoint);
console.log('距离:', hit.distance);
}
点击拾取 #
javascript
scene.onPointerDown = function(evt, pickResult) {
if (pickResult.hit) {
const mesh = pickResult.pickedMesh;
console.log('点击了:', mesh.name);
// 高亮显示
highlightLayer.addMesh(mesh, BABYLON.Color3.Yellow());
}
};
射线调试 #
javascript
// 显示射线
const rayHelper = new BABYLON.RayHelper(ray);
rayHelper.show(scene, new BABYLON.Color3(1, 1, 0));
网格碰撞 #
碰撞检测 #
javascript
// 启用碰撞
mesh.checkCollisions = true;
// 设置碰撞边界
mesh.ellipsoid = new BABYLON.Vector3(1, 2, 1);
// 地面碰撞
ground.checkCollisions = true;
相机碰撞 #
javascript
// 相机碰撞
camera.checkCollisions = true;
camera.applyGravity = true;
camera.ellipsoid = new BABYLON.Vector3(1, 1, 1);
网格高级操作 #
布尔运算 #
javascript
// 使用 CSG(构造实体几何)
const csg1 = BABYLON.CSG.FromMesh(mesh1);
const csg2 = BABYLON.CSG.FromMesh(mesh2);
// 并集
const union = csg1.union(csg2);
// 交集
const intersect = csg1.intersect(csg2);
// 差集
const subtract = csg1.subtract(csg2);
// 转换回网格
const resultMesh = union.toMesh('result', material, scene);
挤出 #
javascript
// 从形状挤出
const shape = [
new BABYLON.Vector3(-1, 0, 0),
new BABYLON.Vector3(1, 0, 0),
new BABYLON.Vector3(1, 2, 0),
new BABYLON.Vector3(-1, 2, 0)
];
const extruded = BABYLON.MeshBuilder.ExtrudePolygon('extruded', {
shape: shape,
depth: 2
}, scene);
拉伸 #
javascript
// 沿路径拉伸
const path = [
new BABYLON.Vector3(0, 0, 0),
new BABYLON.Vector3(0, 3, 0),
new BABYLON.Vector3(2, 5, 0)
];
const tube = BABYLON.MeshBuilder.CreateTube('tube', {
path: path,
radius: 0.5,
tessellation: 16
}, scene);
顶点操作 #
javascript
// 获取顶点数据
const positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
// 修改顶点
for (let i = 0; i < positions.length; i += 3) {
positions[i] += Math.random() * 0.1; // x
positions[i + 1] += Math.random() * 0.1; // y
positions[i + 2] += Math.random() * 0.1; // z
}
// 更新顶点数据
mesh.updateVerticesData(BABYLON.VertexBuffer.PositionKind, positions);
// 重新计算法线
mesh.createNormals(true);
实战:网格管理器 #
javascript
class MeshManager {
constructor(scene) {
this.scene = scene;
this.meshes = new Map();
}
createBox(name, options = {}) {
const mesh = BABYLON.MeshBuilder.CreateBox(name, {
width: options.width || 1,
height: options.height || 1,
depth: options.depth || 1
}, this.scene);
mesh.position = options.position || BABYLON.Vector3.Zero();
if (options.material) {
mesh.material = options.material;
}
this.meshes.set(name, mesh);
return mesh;
}
createSphere(name, options = {}) {
const mesh = BABYLON.MeshBuilder.CreateSphere(name, {
diameter: options.diameter || 1,
segments: options.segments || 32
}, this.scene);
mesh.position = options.position || BABYLON.Vector3.Zero();
if (options.material) {
mesh.material = options.material;
}
this.meshes.set(name, mesh);
return mesh;
}
async loadModel(name, url, options = {}) {
const result = await BABYLON.SceneLoader.ImportMeshAsync(
'',
'',
url,
this.scene
);
const rootMesh = result.meshes[0];
rootMesh.name = name;
rootMesh.position = options.position || BABYLON.Vector3.Zero();
if (options.scale) {
rootMesh.scaling = new BABYLON.Vector3(
options.scale,
options.scale,
options.scale
);
}
this.meshes.set(name, rootMesh);
return result;
}
get(name) {
return this.meshes.get(name);
}
remove(name) {
const mesh = this.meshes.get(name);
if (mesh) {
mesh.dispose();
this.meshes.delete(name);
}
}
clear() {
this.meshes.forEach(mesh => mesh.dispose());
this.meshes.clear();
}
createInstances(name, positions) {
const source = this.meshes.get(name);
if (!source) return [];
return positions.map((pos, i) => {
const instance = source.createInstance(`${name}_instance_${i}`);
instance.position = pos;
return instance;
});
}
}
// 使用
const meshManager = new MeshManager(scene);
meshManager.createBox('box1', {
width: 2,
height: 1,
depth: 1,
position: new BABYLON.Vector3(0, 0.5, 0)
});
meshManager.createSphere('sphere1', {
diameter: 1,
position: new BABYLON.Vector3(2, 0.5, 0)
});
// 创建实例
meshManager.createInstances('box1', [
new BABYLON.Vector3(4, 0.5, 0),
new BABYLON.Vector3(6, 0.5, 0),
new BABYLON.Vector3(8, 0.5, 0)
]);
下一步 #
现在你已经掌握了网格几何体,接下来学习 动画系统,了解如何为物体添加动画效果!
最后更新:2026-03-29