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