Threebox and Mapbox: Why are textures and shapes disappearing on consecutive instances of the same GLTF model?

1.3k views Asked by At

I am adding multiple instances of the same GLTF model to a scene using Mapbox-gl (2.2.0) and the excellent Threebox (2.2.3) plugin.

The first model renders correctly, the second model exists in the scene, but loses textures and/or shapes.

Different models can be loaded and they do not conflict with each other, however the same behaviour occurs where the second and consecutive instances of each model lose textures and/or shapes.

Two different (but similar) models, loaded twice. The first instance of each model renders correctly, the second instance does not

Pre-Mapbox 2.0 release this was working ok, so I presume it's either a bug or a feature I've misunderstood. It would be great to get this working with 3D terrain on the newest version.

Below is the relevant code, stripped right back:

    let map = new mapboxgl.Map({
        style: "mapbox://styles/mapbox/satellite-v9?optimize=true",
        center: [7.059806068014609, 46.058219779837316],
        zoom: 9.848554211380023,
        pitch: 85,
        bearing: -154.1,
        container: 'map',
        antialias: true, 
        hash: true
    });

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

        map.addLayer({
            id: '3D-overlay',
            type: 'custom',
            renderingMode: '3d',
            onAdd: function (map, mbxContext) {

                window.tb = new Threebox(
                    map,
                    map.getCanvas().getContext('webgl'),{});

            },

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

        addBike(1);
        addBike(2);

    });

    function addBike(num){

        var options = {
            obj: "./gltf/cyclist/scene.gltf",
            type: 'gltf',
            scale: 10,
            units: 'meters',
            rotation: {x: 90, y:177, z:0},
            anchor: 'auto'
        }

        tb.loadObj(options, function (model) {

            tb.add(model);

            model.setCoords([6.927566+(num/10), 45.984111 + (num/10), 4000]);

            model.traverse(function (object) {
                object.frustumCulled = false;
            });

            model.playAnimation({ animation: 0, duration: 1000000000 });

            model.selected = true;

        })

    }

Here is a github repo with the files:

https://github.com/nickshreck/threebox-mapbox-gltf-issue.git

Run npm i, put a mapbox token into main.js and then npm run dev

Many thanks

1

There are 1 answers

4
jscastro On BEST ANSWER

Thanks for reporting such a tricky issue, in a so detailed and clear way. It helped me to identify an issue in the code of Threebox. This issue has been resolved adding a new attribute to tb.loadObj that now accepts clone: false. It's already available in the code repo, and it will be published as npm module v2.2.4 soon. In the meantime you can use the bundle file from github.

Your function addBike would look like this now:

    function addBike(num){

        var options = {
            obj: "./gltf/cyclist/scene.gltf",
            type: 'gltf',
            scale: 10,
            units: 'meters',
            rotation: {x: 90, y:177, z:0},
            anchor: 'auto',
            clone: false //objects won't be cloned
        }

        tb.loadObj(options, function (model) {

            tb.add(model);

            model.setCoords([6.927566+(num/10), 45.984111 + (num/10), 4000]);

            model.traverse(function (object) {
                object.frustumCulled = false;
            });

            model.playAnimation({ animation: 0, duration: 1000000000 });

            model.selected = true;

        })

    }

I also recommend you to declare tb object outside the addLayer method instead of inside. That will fire some automatic behaviors related to real sunlight and terrain layers, and remove the duplicated lights.

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

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

            map.addLayer({
                id: '3D-overlay',
                type: 'custom',
                renderingMode: '3d',
                onAdd: function (map, mbxContext) {

                    addBike(3);
                    addBike(4);

                },

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


        });

enter image description here

Thanks again!