Add a 3D Model with BabylonJS
Use a custom style layer with babylon.js to add a 3D model to the map. Requires Trimble Maps v4.0.0 or later.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Add a 3D model with babylon.js</title>
<link rel="stylesheet" href="https://maps-sdk.trimblemaps.com/v4/trimblemaps-4.2.5.css" />
<script src="https://maps-sdk.trimblemaps.com/v4/trimblemaps-4.2.5.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
html,
body,
#map {
height: 100%;
}
</style>
</head>
<body>
<script src="https://unpkg.com/babylonjs@5.42.2/babylon.js"></script>
<script src="https://unpkg.com/babylonjs-loaders@5.42.2/babylonjs.loaders.min.js"></script>
<div id="map"></div>
<script>
const BABYLON = window.BABYLON;
TrimbleMaps.setAPIKey('YOUR_API_KEY_HERE');
const map = (window.map = new TrimbleMaps.Map({
container: "map",
style: TrimbleMaps.Common.Style.TRANSPORTATION,
zoom: 18,
center: [148.9819, -35.3981],
pitch: 60,
antialias: true, // create the gl context with MSAA antialiasing, so custom layers are antialiased
}));
// World matrix parameters
const worldOrigin = [148.9819, -35.39847];
const worldAltitude = 0;
// Trimblemaps.js default coordinate system (no rotations)
// +x east, -y north, +z up
//var worldRotate = [0, 0, 0];
// Babylon.js default coordinate system
// +x east, +y up, +z north
const worldRotate = [Math.PI / 2, 0, 0];
// Calculate mercator coordinates and scale
const worldOriginMercator = TrimbleMaps.MercatorCoordinate.fromLngLat(worldOrigin, worldAltitude);
const worldScale = worldOriginMercator.meterInMercatorCoordinateUnits();
// Calculate world matrix
const worldMatrix = BABYLON.Matrix.Compose(
new BABYLON.Vector3(worldScale, worldScale, worldScale),
BABYLON.Quaternion.FromEulerAngles(worldRotate[0], worldRotate[1], worldRotate[2]),
new BABYLON.Vector3(worldOriginMercator.x, worldOriginMercator.y, worldOriginMercator.z),
);
// configuration of the custom layer for a 3D model per the CustomLayerInterface
const customLayer = {
id: "3d-model",
type: "custom",
renderingMode: "3d",
onAdd(map, gl) {
this.engine = new BABYLON.Engine(
gl,
true,
{
useHighPrecisionMatrix: true, // Important to prevent jitter at mercator scale
},
true,
);
this.scene = new BABYLON.Scene(this.engine);
this.scene.autoClear = false;
this.scene.detachControl();
this.scene.beforeRender = () => {
this.engine.wipeCaches(true);
};
// create simple camera (will have its project matrix manually calculated)
this.camera = new BABYLON.Camera("Camera", new BABYLON.Vector3(0, 0, 0), this.scene);
// create simple light
const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 0, 100), this.scene);
light.intensity = 0.7;
// Add debug axes viewer, positioned at origin, 10 meter axis lengths
new BABYLON.AxesViewer(this.scene, 10);
// load GLTF model in to the scene
BABYLON.SceneLoader.LoadAssetContainerAsync("https://developer.trimblemaps.com/maps-sdk/3d-model-demo/34M_17.gltf", "", this.scene).then((modelContainer) => {
modelContainer.addAllToScene();
const rootMesh = modelContainer.createRootMesh();
// If using trimblemaps.js coordinate system (+z up)
//rootMesh.rotation.x = Math.PI/2
// Create a second mesh
const rootMesh2 = rootMesh.clone();
// Position in babylon.js coordinate system
rootMesh2.position.x = 25; // +east, meters
rootMesh2.position.z = 25; // +north, meters
});
this.map = map;
},
render(gl, matrix) {
const cameraMatrix = BABYLON.Matrix.FromArray(matrix);
// world-view-projection matrix
const wvpMatrix = worldMatrix.multiply(cameraMatrix);
this.camera.freezeProjectionMatrix(wvpMatrix);
this.scene.render(false);
this.map.triggerRepaint();
},
};
map.on("style.load", () => {
map.addLayer(customLayer);
});
</script>
</body>
</html>
Add a 3D Model with BabylonJS
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Add a 3D model with babylon.js</title>
<link rel="stylesheet" href="https://maps-sdk.trimblemaps.com/v4/trimblemaps-4.2.5.css" />
<script src="https://maps-sdk.trimblemaps.com/v4/trimblemaps-4.2.5.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
html,
body,
#map {
height: 100%;
}
</style>
</head>
<body>
<script src="https://unpkg.com/babylonjs@5.42.2/babylon.js"></script>
<script src="https://unpkg.com/babylonjs-loaders@5.42.2/babylonjs.loaders.min.js"></script>
<div id="map"></div>
<script>
const BABYLON = window.BABYLON;
TrimbleMaps.setAPIKey('YOUR_API_KEY_HERE');
const map = (window.map = new TrimbleMaps.Map({
container: "map",
style: TrimbleMaps.Common.Style.TRANSPORTATION,
zoom: 18,
center: [148.9819, -35.3981],
pitch: 60,
antialias: true, // create the gl context with MSAA antialiasing, so custom layers are antialiased
}));
// World matrix parameters
const worldOrigin = [148.9819, -35.39847];
const worldAltitude = 0;
// Trimblemaps.js default coordinate system (no rotations)
// +x east, -y north, +z up
//var worldRotate = [0, 0, 0];
// Babylon.js default coordinate system
// +x east, +y up, +z north
const worldRotate = [Math.PI / 2, 0, 0];
// Calculate mercator coordinates and scale
const worldOriginMercator = TrimbleMaps.MercatorCoordinate.fromLngLat(worldOrigin, worldAltitude);
const worldScale = worldOriginMercator.meterInMercatorCoordinateUnits();
// Calculate world matrix
const worldMatrix = BABYLON.Matrix.Compose(
new BABYLON.Vector3(worldScale, worldScale, worldScale),
BABYLON.Quaternion.FromEulerAngles(worldRotate[0], worldRotate[1], worldRotate[2]),
new BABYLON.Vector3(worldOriginMercator.x, worldOriginMercator.y, worldOriginMercator.z),
);
// configuration of the custom layer for a 3D model per the CustomLayerInterface
const customLayer = {
id: "3d-model",
type: "custom",
renderingMode: "3d",
onAdd(map, gl) {
this.engine = new BABYLON.Engine(
gl,
true,
{
useHighPrecisionMatrix: true, // Important to prevent jitter at mercator scale
},
true,
);
this.scene = new BABYLON.Scene(this.engine);
this.scene.autoClear = false;
this.scene.detachControl();
this.scene.beforeRender = () => {
this.engine.wipeCaches(true);
};
// create simple camera (will have its project matrix manually calculated)
this.camera = new BABYLON.Camera("Camera", new BABYLON.Vector3(0, 0, 0), this.scene);
// create simple light
const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 0, 100), this.scene);
light.intensity = 0.7;
// Add debug axes viewer, positioned at origin, 10 meter axis lengths
new BABYLON.AxesViewer(this.scene, 10);
// load GLTF model in to the scene
BABYLON.SceneLoader.LoadAssetContainerAsync("https://developer.trimblemaps.com/maps-sdk/3d-model-demo/34M_17.gltf", "", this.scene).then((modelContainer) => {
modelContainer.addAllToScene();
const rootMesh = modelContainer.createRootMesh();
// If using trimblemaps.js coordinate system (+z up)
//rootMesh.rotation.x = Math.PI/2
// Create a second mesh
const rootMesh2 = rootMesh.clone();
// Position in babylon.js coordinate system
rootMesh2.position.x = 25; // +east, meters
rootMesh2.position.z = 25; // +north, meters
});
this.map = map;
},
render(gl, matrix) {
const cameraMatrix = BABYLON.Matrix.FromArray(matrix);
// world-view-projection matrix
const wvpMatrix = worldMatrix.multiply(cameraMatrix);
this.camera.freezeProjectionMatrix(wvpMatrix);
this.scene.render(false);
this.map.triggerRepaint();
},
};
map.on("style.load", () => {
map.addLayer(customLayer);
});
</script>
</body>
</html>