2

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

nickshreck
  • 23
  • 5
  • Hi, I'm maintaining that version of [Threebox](https://github.com/jscastro76/threebox), I'll take a look to it to identify what's producing the issue. Seems like a [bug reported here](https://github.com/jscastro76/threebox/issues/204) but in that case it was an issue with the model – jscastro May 10 '21 at 09:18
  • Hello, I am well aware of your stellar work. Thank you, I'll take a look at the thread and see if any of the solutions work, else any help you can give is greatly appreciated. Your 2.2.3 update fixed a troublesome model altitude/height bug, many thanks for that too. – nickshreck May 10 '21 at 09:43
  • 1
    Just checking the model, it seems right, so the problem could be related to the major improvements in performance cloning the model (including textures). I'm thinking seriously on adding an option to `tb.addModel` that allows to not clone the model. – jscastro May 10 '21 at 09:47
  • 1
    It's a terrible hack, but simply reloading the same object under a different name achieves the desired end result. – nickshreck May 10 '21 at 10:33
  • 1
    Hummmm... I forgot that!! not so bad hack because it keeps the best of the performance changes (textures cloned) without impacting in the animations... BTW I should have kept the option to load the objects without cloning, in that moment I was struggling with serious memory issues and I made clone by default but opening a task to add the option to avoid cloning and do always full load. – jscastro May 10 '21 at 10:38
  • 1
    Thank you for your help in confirming the issue and identifying the likely cause. Threebox is incredible and opens up a world of possibility for Mapbox, especially now they've gone 3D with the environments. I will keenly follow your updates and thank you again for your help toward the larger community. And thank you for the new task, that will be great. – nickshreck May 10 '21 at 10:38
  • 1
    No, thank you for reporting it, I did nothing... you made it! :-) – jscastro May 10 '21 at 10:40
  • 1
    obj: './cycle/cycle.gltf?='+Math.random() – nickshreck May 10 '21 at 10:50
  • nice one... already added the task to solve the problem [from the root](https://github.com/jscastro76/threebox/issues/245) – jscastro May 10 '21 at 10:55
  • Loving your work – nickshreck May 10 '21 at 10:59

1 Answers1

1

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!

jscastro
  • 3,422
  • 1
  • 9
  • 27
  • 1
    BTW, I've seen in your code the import like this... `import Threebox from 'threebox-plugin/src/Threebox.js'`, that I don't understand how it works, honestly! I'd recommend you to import like this `import { Threebox } from 'threebox-plugin';` – jscastro May 12 '21 at 11:07
  • 1
    This is beautiful, thank you. I've pulled from the repo and everything is working as expected. I've completely relied upon Threebox to get me through some difficult problems in the last year so I'm pleased to hear that I've been of some help in return. Thank you also for the tip about declaring the tb object outside, I've taken your advice. And about the import recommendation too! – nickshreck May 12 '21 at 12:38
  • Do not hesitate to open an issue in the repo or here if you have any problem. I’ll try to help or provide a workaround ASAP – jscastro May 12 '21 at 21:00
  • 1
    You are an absolute legend. I'm furiously building now and trying to find out what she is really capable of, so I will do exactly that when I find something interesting for you! Thank you again, speak soon. – nickshreck May 13 '21 at 12:02