A TypeScript library for integrating Cesium and Babylon.js. This package implements camera motion and lighting synchronization between Cesium and Babylon.js scenes, and internally manages the canvases of both engines for seamless integration.
First, install this package:
npm install cesium-babylon-fusion
Then, install the required peer dependencies:
npm install @babylonjs/core cesium
Ensure your build system properly handles Cesium's static assets. For example, if you're using Vite:
// vite.config.ts
import { defineConfig } from 'vite';
import cesium from 'vite-plugin-cesium'; // Need to install this plugin first
export default defineConfig({
plugins: [cesium()]
});
In your main entry file:
import 'cesium/Build/Cesium/Widgets/widgets.css';
Here's a basic example:
import { CesiumBabylonFusion } from 'cesium-babylon-fusion';
import * as Cesium from 'cesium';
import 'cesium/Build/Cesium/Widgets/widgets.css';
import * as BABYLON from '@babylonjs/core';
// Create container
const container = document.createElement('div');
container.style.width = '100%';
container.style.height = '100%';
container.style.position = 'relative';
document.body.appendChild(container);
// Initialize fusion
const fusion = new CesiumBabylonFusion({
container: container,
cesiumOptions: {
terrainProvider: Cesium.createWorldTerrain(),
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
})
},
// Set Beijing as the base point
basePoint: Cesium.Cartesian3.fromDegrees(116.391, 39.904, 0),
// Optional Babylon.js engine options
babylonOptions: {
alpha: true,
antialias: true
}
});
// Access individual engines
const cesiumViewer = fusion.cesiumViewer;
const babylonScene = fusion.babylonScene;
// Clean up resources
function cleanup() {
fusion.dispose();
}
You can disable automatic rendering and control it manually:
const fusion = new CesiumBabylonFusion({
container: container,
autoRender: false // Disable automatic rendering
});
// Manually trigger render when needed
function animate() {
fusion.render();
requestAnimationFrame(animate);
}
animate();
You can customize the lighting behavior:
const fusion = new CesiumBabylonFusion({
container: container,
enableLightSync: false, // Disable automatic lighting sync
enableShadow: true, // Enable shadow generation
lightDistance: 1000, // Set the distance of the directional light
showSunDirectionLine: true // Show debug line for sun direction
});
The library supports three different camera control modes:
const fusion = new CesiumBabylonFusion({
container: container,
controlMode: 'auto', // 'cesium' | 'babylon' | 'auto'
autoSwitchDistance: 1000 // Distance switching threshold for auto mode (in meters)
});
// You can also change the control mode at runtime
fusion.setControlMode('babylon');
// Dynamically set the switching distance for auto mode
fusion.setAutoSwitchDistance(1500);
// Get current control mode
console.log('Current mode:', fusion.controlMode);
console.log('Actual mode:', fusion.actualControlMode);
Control Mode Details:
'cesium': Cesium controls the camera, Babylon.js follows
'babylon': Babylon.js controls the camera, Cesium follows
'auto': Automatically switches between modes based on camera distance to base point
You can handle click events on Babylon.js meshes through Cesium's viewer:
const fusion = new CesiumBabylonFusion({
container: container,
onMeshPicked: (mesh) => {
if (mesh) {
console.log('Clicked mesh:', mesh.name);
// Handle the clicked mesh
}
}
});
Main class handling the integration between Cesium and Babylon.js.
interface CesiumBabylonFusionOptions {
container: HTMLDivElement; // Container element for both canvases
cesiumOptions?: Cesium.Viewer.ConstructorOptions; // Optional Cesium viewer options
babylonOptions?: BABYLON.EngineOptions; // Optional Babylon.js engine options
basePoint?: Cesium.Cartesian3; // Optional coordinate system base point
autoRender?: boolean; // Enable automatic rendering (default: true)
enableLightSync?: boolean; // Enable lighting sync (default: true)
enableShadow?: boolean; // Enable shadow generation (default: false)
lightDistance?: number; // Distance of the directional light (default: 100)
showSunDirectionLine?: boolean; // Show debug line for sun direction (default: false)
controlMode?: 'cesium' | 'babylon' | 'auto'; // Camera control mode (default: 'cesium')
autoSwitchDistance?: number; // Distance switching threshold for auto mode in meters (default: 1000)
onMeshPicked?: (mesh: BABYLON.AbstractMesh | null) => void; // Callback for mesh click events
}
cesiumViewer: Get the Cesium viewer instancebabylonScene: Get the Babylon.js scene instancebabylonEngine: Get the Babylon.js engine instancesunDirection: Get the current sun direction vector (in Babylon coordinate system)controlMode: Get the current control modeactualControlMode: Get the actual control mode (useful in auto mode)babylonCameraController: Get the Babylon.js camera controller (only available in babylon control mode)shadowGenerator: Get the shadow generator instance (external meshes need addShadowCaster to have shadows)render(): Manually trigger a render framesetControlMode(mode: 'cesium' | 'babylon' | 'auto'): Change the camera control modesetAutoSwitchDistance(distance: number): Set the distance threshold for auto modecartesianToBabylon(cartesian: Cesium.Cartesian3): BABYLON.Vector3: Convert Cesium coordinates to Babylon coordinateslonLatToBabylon(longitude: number, latitude: number, height?: number): BABYLON.Vector3: Convert longitude/latitude coordinates to Babylon coordinatesbabylonToCartesian(vector: BABYLON.Vector3): Cesium.Cartesian3: Convert Babylon coordinates to Cesium coordinatesdispose(): Clean up resources, stop render loop, and remove canvasesThe library automatically parents new meshes to ensure proper coordinate system alignment:
// Create a new mesh
const box = BABYLON.MeshBuilder.CreateBox("box", {}, fusion.babylonScene);
// The mesh will be automatically parented correctly, no manual setup needed
The package creates two canvases in the provided container:
The package automatically configures UI elements for optimal interaction:
Uses a unified render loop executing in the following order:
While this package handles the integration of Cesium and Babylon.js, you still need to:
Cesium.Cartesian3)The package automatically handles coordinate conversion between Cesium and Babylon.js. However, if you need to handle coordinates yourself, note that:
basePoint to set the origin of the local coordinate systemCheck out the examples directory for more detailed examples:
basic.html: Basic setup and usageHere's a comprehensive example showing how to set up the fusion with shadows, create meshes, and handle camera positioning:
const fusion = new CesiumBabylonFusion({
container: container.value,
basePoint: Cesium.Cartesian3.fromDegrees(120, 30, 0), // Set base point to Hangzhou
cesiumOptions: {
timeline: true,
animation: true,
},
enableLightSync: true,
enableShadow: true,
showSunDirectionLine: true,
onMeshPicked,
});
const { viewer, scene } = fusion;
// Enable lighting on Cesium globe
viewer.scene.globe.enableLighting = true;
// Create a red box
const mesh = BABYLON.MeshBuilder.CreateBox("mesh", { size: 10 }, scene);
const material = new BABYLON.StandardMaterial("material", scene);
material.diffuseColor = new BABYLON.Color3(1, 0, 0);
mesh.material = material;
mesh.position = new BABYLON.Vector3(0, 10, 0);
// Add the box as a shadow caster
fusion.shadowGenerator.addShadowCaster(mesh);
// Create a green ground that receives shadows
const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 100, height: 100 }, scene);
const groundMaterial = new BABYLON.StandardMaterial("groundMaterial", scene);
groundMaterial.diffuseColor = new BABYLON.Color3(0, 1, 0);
ground.material = groundMaterial;
ground.receiveShadows = true;
// Move camera to view the scene
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(120, 30, 10),
});
This example demonstrates:
Contributions are welcome! Please feel free to submit a Pull Request.
MIT