• Three.js:2010 年诞生,社区庞大、生态成熟,以轻量灵活著称,适合追求自定义和极致控制的开发者。

  • Babylon.js:2013 年由微软推出,集成度高、工具链完善,自带很多 "开箱即用" 的功能,更像一个 "batteries-included" 的完整解决方案。

两者核心目标一致 —— 在浏览器中渲染 3D 内容,但实现方式各有侧重。

核心概念对比

THREE.WebGLRenderer

Engine

负责将 3D 场景渲染到 canvas 上

THREE.Scene

Scene

3D 世界的容器,所有物体都需加入其中

THREE.Camera

Camera(系列)

定义 "观察者" 的视角和位置

THREE.Mesh

Mesh

几何体 + 材质的组合体,可直接渲染

THREE.Geometry

MeshBuilder

定义物体的形状(Babylon 更倾向于通过工具类创建)

THREE.Material

Material(系列)

定义物体的外观(颜色、纹理等)

THREE.Light

Light(系列)

提供光照,影响物体的可见性和质感

实战对比

1. 环境准备:依赖安装

  • Three.js 通常直接引入核心库:

npm install three @react-three/fiber
  • Babylon.js 的安装方式类似,但核心模块划分更细致:

npm install @babylonjs/core  # 核心引擎
# 如需React集成工具,可额外安装:
# npm install @babylonjs/react-native

2. 基础场景搭建:从渲染器到场景

Three.js 的典型初始化:

import * as THREE from 'three';

// 创建渲染器
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setSize(width, height);

// 创建场景
const scene = new THREE.Scene();

Babylon.js 的对应实现:

import { Engine, Scene } from '@babylonjs/core';

// 创建引擎(相当于Three.js的Renderer)
const engine = new Engine(canvasRef.current, true);  // 第二个参数开启抗锯齿

// 创建场景(与Three.js逻辑一致)
const scene = new Scene(engine);
  • 关键差异:Babylon.js 用Engine封装了渲染逻辑,不仅包含渲染功能,还负责管理渲染循环、窗口大小适配等底层操作,比 Three.js 的Renderer职责更全面。

3. 相机:控制 "观察视角"

Three.js 中常用轨道控制器:

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// 创建相机
const camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000);
camera.position.z = 5;

// 添加轨道控制器(需额外引入)
const controls = new OrbitControls(camera, renderer.domElement);

Babylon.js 的对应实现:

import { ArcRotateCamera } from '@babylonjs/core';

// 创建ArcRotateCamera(自带轨道控制功能)
const camera = new ArcRotateCamera(
  "camera",          // 名称
  0,                 // 初始方位角(弧度)
  Math.PI / 3,       // 初始仰角(弧度)
  10,                // 与目标点的距离
  Vector3.Zero(),    // 目标点坐标
  scene              // 所属场景
);
// 绑定控制器(内置功能,无需额外引入)
camera.attachControl(canvasRef.current, true);
  • 关键差异:Babylon.js 的ArcRotateCamera内置了类似 Three.jsOrbitControls的交互功能,无需额外引入控制器库,开箱即用。

4. 光照:让物体 "可见"

  • Three.js 和 Babylon.js 的光照类型高度对应,但参数设计略有不同:

Three.js 中的光照示例:

// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
scene.add(ambientLight);

// 点光源
const pointLight = new THREE.PointLight(0xffcc99, 0.8);
pointLight.position.set(0, 5, 0);
scene.add(pointLight);

Babylon.js 的对应实现:

import { HemisphericLight, PointLight, Color3 } from '@babylonjs/core';

// 环境光(HemisphericLight比Three的AmbientLight更真实,模拟天地光)
const hemisphericLight = new HemisphericLight(
  "hemisphericLight",
  new Vector3(0, 1, 0),  // 光源方向
  scene
);
hemisphericLight.intensity = 0.3;

// 点光源
const pointLight = new PointLight(
  "pointLight",
  new Vector3(0, 5, 0),  // 位置
  scene
);
pointLight.intensity = 0.8;
pointLight.diffuse = new Color3(1, 0.8, 0.6);  // 用RGB值定义颜色(1对应255)
  • 关键差异

    • Babylon.js 的HemisphericLight比 Three.js 的AmbientLight更复杂,能模拟天空和地面的不同光照颜色,效果更自然;

    • 颜色定义方式不同:Three.js 常用十六进制(如0xffcc99),Babylon.js 常用Color3对象(RGB 值范围 0-1)。

5. 几何体与材质:构建可见物体

Three.js 的几何体创建:

// 创建立方体
const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshStandardMaterial({ color: 0xff5555 });
const cube = new THREE.Mesh(geometry, material);
cube.position.set(-3, 1, 0);
scene.add(cube);

Babylon.js 的对应实现:

import { MeshBuilder, StandardMaterial, Color3 } from '@babylonjs/core';

// 创建立方体(通过MeshBuilder工具类)
const box = MeshBuilder.CreateBox("box", { size: 2 }, scene);
box.position = new Vector3(-3, 1, 0);  // 位置设置更直观

// 创建材质
const boxMaterial = new StandardMaterial("boxMaterial", scene);
boxMaterial.diffuseColor = new Color3(0.8, 0.3, 0.3);  // 红色(RGB 0.8,0.3,0.3)
box.material = boxMaterial;
  • 关键差异

    • Babylon.js 通过MeshBuilder工具类创建几何体(如CreateBoxCreateSphere),比 Three.js 的BoxGeometry等构造函数更直观;

    • 位置、旋转等属性设置更简洁,直接赋值Vector3对象即可,无需调用set方法。

6. 动画:让物体 "动起来"

Three.js 的动画实现(需手动更新):

function animate() {
  requestAnimationFrame(animate);
  // 手动更新旋转
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

Babylon.js 的动画系统(声明式关键帧):

import { Animation } from '@babylonjs/core';

// 创建动画(声明式定义关键帧)
const boxAnimation = new Animation(
  "boxAnimation",
  "rotation.y",  // 要动画的属性
  30,            // 帧率
  Animation.ANIMATIONTYPE_FLOAT,
  Animation.ANIMATIONLOOPMODE_CYCLE  // 循环模式
);

// 定义关键帧
const keyFrames = [
  { frame: 0, value: 0 },
  { frame: 120, value: 2 * Math.PI }  // 120帧完成360度旋转
];
boxAnimation.setKeys(keyFrames);
box.animations = [boxAnimation];

// 播放动画(自动循环,无需手动更新)
scene.beginAnimation(box, 0, 120, true);
  • 关键差异

    • Babylon.js 内置了完整的动画系统,支持关键帧定义,无需像 Three.js 那样在渲染循环中手动更新属性;

    • 动画循环、速度控制等功能开箱即用,适合复杂动画序列。

7. 交互:响应鼠标点击

Three.js 的射线检测:

import { Raycaster } from 'three';

const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

function onMouseClick(event) {
  // 计算鼠标位置
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  
  // 射线检测
  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects(scene.children);
  
  if (intersects.length > 0) {
    // 改变颜色
    intersects[0].object.material.color.set(Math.random() * 0xffffff);
  }
}
window.addEventListener('click', onMouseClick);

Babylon.js 的交互实现:

// 场景内置射线检测,无需手动创建射线
scene.onPointerDown = function (evt) {
  const pickResult = scene.pick(scene.pointerX, scene.pointerY);
  if (pickResult.hit) {
    const hitMesh = pickResult.pickedMesh;
    // 随机改变颜色
    const material = hitMesh.material;
    if (material) {
      material.diffuseColor = new Color3(
        Math.random(),
        Math.random(),
        Math.random()
      );
    }
  }
};
  • 关键差异:Babylon.js 的scene.pick方法封装了射线检测逻辑,无需像 Three.js 那样手动创建Raycaster和计算鼠标坐标,交互实现更简洁。

8. 渲染循环与资源清理

Three.js 的渲染循环:

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

// 清理(需手动处理)
window.removeEventListener('resize', onWindowResize);

Babylon.js 的渲染循环:

// 启动渲染循环(引擎自动管理)
engine.runRenderLoop(() => {
  scene.render();
});

// 窗口大小适配(内置方法)
window.addEventListener('resize', () => {
  engine.resize();
});

// 清理函数(组件卸载时)
return () => {
  engine.dispose();  // 一键释放所有资源
};
  • 关键差异:Babylon.js 的Engine类自动管理渲染循环,且dispose方法会统一释放所有资源(包括场景、相机、材质等),比 Three.js 的手动清理更省心。

9. 物理引擎

一、物理引擎的集成方式

维度

Three.js

Babylon.js

核心依赖

无内置物理引擎,需依赖第三方库(如 Cannon.js、Ammo.js、Rapier.js 等)

内置 Ammo.js(基于 Bullet 物理引擎的 WebAssembly 移植版)作为官方物理引擎

集成复杂度

需手动引入第三方库,自行编写 “3D 对象 - 物理体” 绑定逻辑,新手易踩坑

物理引擎与核心引擎深度整合,提供统一 API,无需手动处理底层绑定

官方支持

无官方维护的物理模块,第三方库需自行适配版本,可能存在兼容性问题

物理引擎作为核心功能之一,与 Babylon.js 版本同步更新,官方文档完整

物理世界初始化

  • Three.js
    需先实例化第三方物理引擎的世界(如 CANNON.World),手动设置重力、时间步长,且需在渲染循环中单独更新物理世界状态。
    示例(Cannon.js):

    import * as CANNON from 'cannon-es';
    
    // 初始化物理世界
    const world = new CANNON.World();
    world.gravity.set(0, -9.82, 0); // 设置重力
    world.broadphase = new CANNON.NaiveBroadphase();
    
    // 渲染循环中更新物理
    function animate() {
      requestAnimationFrame(animate);
      world.step(1/60); // 手动更新物理模拟
      // 同步3D模型与物理体位置(需手动写逻辑)
      mesh.position.copy(physicsBody.position);
      renderer.render(scene, camera);
    }

  • Babylon.js
    直接通过 PhysicsImpostor 关联 3D 对象与物理属性,物理世界由引擎自动管理,无需手动初始化 “物理世界” 实例。
    示例:

    // 启用物理引擎(仅需一次)
    scene.enablePhysics(new BABYLON.Vector3(0, -9.81, 0), new BABYLON.AmmoJSPlugin());
    
    // 为物体添加物理属性
    box.physicsImpostor = new BABYLON.PhysicsImpostor(
      box,
      BABYLON.PhysicsImpostor.BoxImpostor, // 碰撞体类型
      { mass: 1, friction: 0.5 }, // 物理参数
      scene
    );

2. 碰撞体类型与灵活性

  • Three.js
    依赖第三方库支持的碰撞体类型(如 Cannon.js 支持盒子、球体、胶囊体等基础形状,复杂形状需手动组合)。若需高精度碰撞(如使用模型顶点数据),需额外处理碰撞体生成逻辑。

  • Babylon.js
    内置多种碰撞体类型(盒子、球体、圆柱体、胶囊体、 mesh 形状等),支持直接基于 3D 模型的顶点数据生成碰撞体(MeshImpostor),无需手动处理复杂形状的碰撞逻辑。
    示例(使用模型本身作为碰撞体):

// 基于模型网格生成碰撞体
complexModel.physicsImpostor = new BABYLON.PhysicsImpostor(
  complexModel,
  BABYLON.PhysicsImpostor.MeshImpostor,
  { mass: 2, restitution: 0.2 },
  scene
);

3. 物理交互与约束

  • Three.js
    约束(如关节、弹簧、马达)需通过第三方库的 API 手动创建,且需手动关联到对应的物理体,代码冗余度高。例如用 Cannon.js 创建铰链约束:

    const hinge = new CANNON.HingeConstraint(
      bodyA, bodyB, 
      { pivotA: new CANNON.Vec3(0, 1, 0) }, // 物体A的约束点
      { pivotB: new CANNON.Vec3(0, -1, 0) } // 物体B的约束点
    );
    world.addConstraint(hinge);

  • Babylon.js
    提供统一的约束 API(如 HingeJointDistanceJointSliderJoint 等),直接通过物理体实例创建,无需手动关联到物理世界,且参数配置更直观。
    示例(创建铰链约束):

const hinge = new BABYLON.HingeJoint(
  {
    mainPivot: new BABYLON.Vector3(0, 1, 0), // 主物体约束点
    connectedPivot: new BABYLON.Vector3(0, -1, 0), // 关联物体约束点
    axis: new BABYLON.Vector3(1, 0, 0) // 旋转轴
  },
  scene
);
// 关联两个物体
hinge.attach(box.physicsImpostor, sphere.physicsImpostor);