Hi!
I have an issue with applying material to meshes loaded from a file; the material does not show.
I think it is related to timing, because the mesh shows visually before console.log outputs information about the mesh and upon inspecting it in the console, the material is set.
Since this is an integration with Maplibre, I cannot use the Playground, sorry for that. Here is the code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add a 3D model with babylon.js</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.js"></script>
<link href="https://unpkg.com/maplibre-gl@2.4.0/dist/maplibre-gl.css" rel="stylesheet" />
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.slim.js'></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 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>
<style type="text/css">
#info {
display: block;
position: relative;
margin: 0px auto;
width: 50%;
padding: 10px;
border: none;
border-radius: 3px;
font-size: 12px;
text-align: center;
color: #222;
background: #fff;
}
</style>
<div id="map"></div>
<pre id="info">abc</pre>
<script>
var BABYLON = window.BABYLON;
// Define the map syle (OpenStreetMap raster tiles)
const style = {
"version": 8,
"sources": {
"osm": {
"type": "raster",
"tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"],
"tileSize": 256,
"attribution": "© OpenStreetMap Contributors",
"maxzoom": 19
}
},
"layers": [
{
"id": "osm",
"type": "raster",
"source": "osm" // This must match the source key above
}
]
};
var map = (window.map = new maplibregl.Map({
container: 'map',
style:
style,
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
var worldOrigin = [148.9819, -35.39847];
var worldAltitude = 0;
// Maplibre.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
var worldRotate = [Math.PI / 2, 0, 0];
// Calculate mercator coordinates and scale
var worldOriginMercator = maplibregl.MercatorCoordinate.fromLngLat(
worldOrigin,
worldAltitude
);
const worldScale = worldOriginMercator.meterInMercatorCoordinateUnits();
// Calculate world matrix
var 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
var customLayer = {
id: '3d-model',
type: 'custom',
renderingMode: '3d',
onAdd: function (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);
const files = [
{
fileName : "34M_17.gltf",
positionX : "0",
positionY : "0"
},
{
fileName : "byggnad.obj",
positionX : "25",
positionY : "0"
},
]
for (let i = 0; i < files.length; i++)
{
// load GLTF model in to the scene
BABYLON.SceneLoader.LoadAssetContainerAsync(
files[i].fileName,
'',
this.scene
).then((modelContainer) => {
const rootMesh = modelContainer.createRootMesh();
rootMesh.name = "min mesh " + i;
rootMesh.position.x = files[i].positionX;
rootMesh.position.y = files[i].positionY;
var mat = new BABYLON.StandardMaterial("mat", this.scene);
mat.emissiveColor = BABYLON.Color3.White();
mat.wireframe = true;
rootMesh.material = mat;
console.log(rootMesh);
modelContainer.addAllToScene();
});
}
this.map = map;
},
render: function (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();
},
raycast: function (point, isClick) {
$('#info').empty();
var ray = this.scene.createPickingRay(point.x, point.y, BABYLON.Matrix.Identity(), this.camera, false);
var hit = this.scene.pickWithRay(ray);
if (hit.pickedMesh){
$('#info').append(hit.pickedMesh.parent.name);
console.log(hit);
}
}
};
map.on('style.load', function () {
map.addLayer(customLayer);
});
map.on('click', function(e) {
customLayer.raycast(e.point, true);
});
</script>
</body>
</html>
Thanks for all help!