jscastro76 / threebox

A Three.js plugin for Mapbox GL JS, with support for animations and advanced 3D rendering.
Other
549 stars 145 forks source link

Loading 3d GLTF spatial model #235

Closed jbbarre closed 3 years ago

jbbarre commented 3 years ago

Threebox version: latest

Question

I want to load a 3d GLTF model in a 3d Mapbox map. The model corresponds to a glacier, whose coordinates are expressed in the web mercator system (EPSG 3857). I choose to work with Threebox as I want to load several dates of the same glacier. As It's really tricky to specify an origin to such a model and as the model itself contain the spatial information, I'm trying to load it directly by not specifying an origin. All the Threebox examples I've checked require an origin. I don't know how to do this, especially since I'm starting with three.js and Mapbox.

The model is available here.

Any suggestion is welcome. Thanks.

jscastro76 commented 3 years ago

Hummm conceptually speaking, to add a 3D model to a Three.js you need at least a point on the scene coordinates to use it as an anchor. If your model contains coordinates (I don’t know well how or where in the gltf model) once the model is loaded you’ll need to read at least one of those values and then position the Threebox anchor in that point using anchor and adjustment properties.

jbbarre commented 3 years ago

Fine, I will find a way to create an anchor. The position of the village church below will certainly help me. thanks.

jscastro76 commented 3 years ago

Hi @jbbarre

I explored your model and I still don't find where that geo data you referred is. Indeed the model scale is very very small... I had to enlarge it x3100 to have the real size.

Having said so, this is my best approach to the size, position of your glacier... image

I have tried to add also a terrain layer, but the layer doesn't match you model and there are also other related issues with terrain layers depth calculation that are not yet fixed.

Here's the relevant code/size/position for your reference

<!doctype html>
<head>
    <title>Glacier</title>
    <meta charset='utf-8'>
    <script src="Scripts/mapbox-gl-2.2.js"></script>
    <link href="Scripts/mapbox-gl-2.2.css" rel="stylesheet" />
    <script src="/Scripts/threebox.js"></script>
    <link href="Styles/threebox.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        html, body, #map {
            height: 100%;
        }

    </style>
</head>
<body>
    <div id='map' class='map' />
    <script>

        mapboxgl.accessToken = 'PASTE YOUR TOKEN HERE';

        //starting location for map
        let popup;
        let minZoom = 12;
        let seconds = 0;
        let date = new Date();
        let mapConfig = {
            PAR: {
                origin: [6.992136, 45.949079, 0], center: [6.98645, 45.95104, 0], zoom: 13, pitch: 59, bearing: 159, scale: 3100, rotation: { x: 0, y: 0, z: 168 },timezone: 'Europe/Paris', obj: './3D/landmarks/glacier_wgs.gltf', 
            },
            names: {
                customLayer: "custom-layer",
                fillExtrusion: "composite-b",
                fillExtrusionLayer: "building-b"
            }
        }
        let point = mapConfig.PAR;

        var map = new mapboxgl.Map({
            style: 'mapbox://styles/mapbox/satellite-v9', 
            center: point.center,
            zoom: point.zoom,
            pitch: point.pitch,
            bearing: point.bearing,
            container: 'map',
            antialias: true, hash: true
        });

        map.addControl(new mapboxgl.NavigationControl());

        window.tb = new Threebox(
            map,
            map.getCanvas().getContext('webgl'),
            {
                realSunlight: true,
                sky: true,
                enableSelectingObjects: true, 
                enableDraggingObjects: true, 
                enableRotatingObjects: true, 
                enableTooltips: true, 
            }
        );

        tb.altitudeStep = 10;
        tb.rotationStep = 1;

        map.on('style.load', function () {

            map.addLayer({
                id: mapConfig.names.customLayer,
                type: 'custom',
                renderingMode: '3d',
                onAdd: function (map, mbxContext) {

                    var options = {
                        obj: mapConfig.PAR.obj,
                        type: 'gltf',
                        scale: mapConfig.PAR.scale,
                        units: 'scene',
                        rotation: mapConfig.PAR.rotation, 
                        anchor: 'center'
                    }

                    tb.loadObj(options, function (model) {
                        model.setCoords(mapConfig.PAR.origin);
                        model.addTooltip("Glacier d'Argentière", true);
                        model.color = 0xffffff;
                        tb.add(model);
                    })

                },

                render: function (gl, matrix) {
                    tb.update();
                }
            });

        });

    </script>
</body>

Hope it helps

jbbarre commented 3 years ago

Thanks, @jscastro76 !

Based on your help, I finally find the right way to manage my GLTF file. The coordinates of the model mesh in WGS84 coordinates system, which unit is degree. This explains why the model is so small. I converted it to a metric CRS and adjust the origin in Blender. The model is properly positioned in Mapbox. See the prototype, I made with the three.js: glacier. Now, I have to test it with threebox to go ahead.

jscastro76 commented 3 years ago

@jbbarre it’s beautiful I’d love to add this example to Threebox whenever you finish and use it also to solve the depth issues with the terrain layers. If you want we could add it to the source adding you as contributor

jbbarre commented 3 years ago

Thanks, @jscastro76. I continue to work on it. As soon as I'll have something stable, I'll let you know.

jscastro76 commented 3 years ago

@jbbarre inspired by your scenario, I finally decided to implement your example using your glacier, your specific needs of mixing the height of the terrain with the 3D model helped me to debug the camera changes required and to implement terrain perspective matrixes calculation. I added your name as contributor to the sample and to the license.txt image