I'm trying to dynamically load a user-loaded gltf model and have that model be placed on top of a map. The second part would be doing the same thing but with IFC model. I'm working with react-map-gl
to create a map and I've been able to place a 3D model on top of the map just like the one described in this example: just by simply putting a gltf url like this one inside deck.gl
's scenegraph
layer. However what I'm having a hard time doing is placing a user-loaded IFC or GLTF model on top of the map. All the example I've seen uses a GLTF url, or some url that comes from arcgis but is there a way to place a user loaded model inside of the scenegraph
layer in deck.gl
?
This is my best attempt at placing a user-uploaded GLTF model which gives me the error message:
deck: loading scenegraph of ScenegraphLayer({id: 'scenegraph-layer'}): No valid loader found (0f3e4b8a-f7d4-4cbd-868e-c4c463552bca, MIME type: not provided, first bytes: not available)
import { useState } from 'react';
import { Map } from 'react-map-gl';
import { ScenegraphLayer } from '@deck.gl/mesh-layers';
import { DeckGL } from 'deck.gl';
import maplibreGl from 'maplibre-gl';
function App() {
const [gltfUrl, setGltfUrl] = useState();
const gltfUpload = (e) => {
const file = e.target.files[0];
const url = URL.createObjectURL(file);
setGltfUrl(url);
};
const layer = new ScenegraphLayer({
id: 'scenegraph-layer',
pickable: true,
data: [
{
name: 'Colma (COLM)',
address: '365 D Street, Colma CA 94014',
exits: 4214,
coordinates: [148.9819, -35.39847],
},
],
scenegraph: gltfUrl,
getPosition: (d) => d.coordinates,
getOrientation: (d) => [0, Math.random() * 180, 90],
sizeScale: 1,
_lighting: 'pbr',
});
return (
<>
<input
type='file'
onChange={gltfUpload}
style={{ zIndex: 10, position: 'fixed' }}
/>
<DeckGL
initialViewState={{
longitude: 148.9819,
latitude: -35.39847,
zoom: 18,
pitch: 60,
}}
controller={true}
layers={[layer]}
>
<Map
mapLib={maplibreGl}
mapStyle='https://api.maptiler.com/maps/basic/style.json?key=get_your_own_OpIi9ZULNHzrESv6T2vL'
/>
</DeckGL>
</>
);
}
export default App;
And this is my best attempt at placing an IFC model using I3SLoader
and web-ifc-three
and this code gives me the error: Uncaught (in promise) Error: Cannot convert supplied data type at getArrayBufferOrStringFromData
import { useState } from 'react';
import maplibregl from 'maplibre-gl';
import DeckGL from '@deck.gl/react';
import { Map } from 'react-map-gl';
import { Tile3DLayer } from '@deck.gl/geo-layers';
import { I3SLoader } from '@loaders.gl/i3s';
import { IFCLoader } from 'web-ifc-three';
function App() {
const [ifcObject, setIfcObject] = useState();
const ifcLoader = new IFCLoader();
const ifcUpload = (e) => {
const file = e.target.files[0];
const url = URL.createObjectURL(file);
ifcLoader.loadAsync(url).then((res) => {
setIfcObject(res);
});
};
const layer = new Tile3DLayer({
id: 'tile-3d-layer',
// Tileset entry point: Indexed 3D layer file url
data: ifcObject,
loader: I3SLoader,
});
return (
<>
<input
type='file'
onChange={ifcUpload}
style={{ zIndex: 10, position: 'fixed' }}
/>
<DeckGL
initialViewState={{
longitude: 148.9819,
latitude: -35.39847,
zoom: 18,
pitch: 60,
}}
controller={true}
layers={[layer]}
>
<Map
mapLib={maplibregl}
mapStyle='https://api.maptiler.com/maps/basic/style.json?key=get_your_own_OpIi9ZULNHzrESv6T2vL'
/>
</DeckGL>
</>
);
}
I honestly have no clue what I'm even doing at this point. I'm pretty lost and I appreciate all the help that I can get. Thanks in advance!