threebox icon indicating copy to clipboard operation
threebox copied to clipboard

realSunLight bug when resizing the navigator viewport

Open picpic1979 opened this issue 3 years ago • 6 comments

Hello,

I don't know if it is a bug or if i missing something but i tried to use realtime sunlight shadows in my 3d map, it work well i have shadows but if i try to rescale my chrome viewport the 3d model appear to be distort

work well Capture_g01 bug when i rescale the viewport Capture_g02

you can see it here http://explorer.newcherbourgstories.com/

If i comment realsunlight : true, it work fine i can rescale the 3d object follow great

`const CreateThreeboxModel = () => {

    var origin = [-1.621463364657315,49.63355377375169, 0];

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


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

        //temps reel des shadows
        let date = new Date();//new Date(2020, 7, 14, 0, 39); // change this UTC date time to show the shadow view
        let time = date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds();
        // let timeInput = document.getElementById('time');
        // let hour = document.getElementById('hour');
        // timeInput.value = time;
        // timeInput.oninput = () => {
        //     time = +timeInput.value;
        //     date.setHours(Math.floor(time / 60 / 60));
        //     date.setMinutes(Math.floor(time / 60) % 60);
        //     date.setSeconds(time % 60);
        //     map.current.triggerRepaint();
        // };
        //

		map.current.addLayer({
			id: 'custom_layer',
			type: 'custom',
			renderingMode: '3d',
			onAdd: function (map,mbxcontext) {

				// import soldier from an external glb file, scaling up its size 20x
				// IMPORTANT: .glb is not a standard MIME TYPE, you'll have to add it to your web server config,
				// otherwise you'll receive a 404 error

                // Attribution: Soldier animated model by T. Choonyung at https://www.mixamo.com
				// from https://www.mixamo.com/#/?page=1&query=vanguard&type=Character
				var options = {
					obj: '../../models/gare.glb',
					type: 'gltf',
                    //bbox: true,
					scale: 1,
					units: 'meters',
                    adjustment: {x: 0.15, y: 0.5, z: 0},//important pour le placement avc de l'offset
					rotation: { x: 90, y: 180, z: 0 }, //default rotation
				    //anchor: 'center'
				}

				window.tb.loadObj(options, function (model) {
					
                    let gare = model.setCoords(origin);
                    gare.addEventListener('SelectedChange', onSelectedChange, false);
                    gare.castShadow = true;
					window.tb.lights.dirLight.target = gare;
					window.tb.add(gare);
                    window.tb.setLayerZoomRange('custom_layer',16,23);
                    loaded();

				})

                const loaded = () => {
                    console.log('loaded');
                }

			},
			render: function (gl, matrix) {
                window.tb.setSunlight(date); //set Sun light for the given datetime and lnglat
                window.tb.update();
			}
		},'blank-test copy');

	});
}`

Thanks for your time again

picpic1979 avatar Jul 15 '21 08:07 picpic1979

It seems that what is happening is that your app is not firing properly the event map.on('resize', ... that automatically will recalculate perspective at CameraSync I've seen sometimes this effect when the web app wraps the map with complex html/css and some transformations are applied by css style properties/classes, or javascript events occurring in async. if this happens, the change being produced at HTML or javascript level is unnoticed by mapbox resize event.

Good news, is that you can force the call to map.resize() when your container resizes... I did something similar in one of my projects with a complex html prototyping and tons of style layers and dynamic javascript applied to the page, in my personal case detecting the change of the container css style through an MutationObserver, I was able to force the resize event.

Hope this helps.

		//[jscastro] MutationObserver checks changes in HTML class and raises an event
		let observer = new MutationObserver(function (mutations) {
			mutations.forEach(function (mutation) {
				if (mutation.attributeName === "class") {
					//console.log(mutation);
					$(mutation.target).trigger('classChange');
				}
			});
		});

		function observe(cssSelector) {
			//[jscastro] We add the observer for the map card that will change on maximize
			let o = observer.observe($(cssSelector)[0], {
				attributes: true
			});
			//[jscastro] on class change for the map card, we resize the map on a 200ms delay
			$(cssSelector).on('classChange', function () {
				window.setTimeout(function () {
					map.resize();
				}, 200);
			});

		}
		observe("mapContainer");
		observe("body");

In your case you will need to identify what changes in your html when you change the viewport size, and add that to the MutationObserver method logic. As you can see I only detect the change of a class mutation.attributeName === "class", in your case it could be any other style property.

jscastro76 avatar Jul 15 '21 09:07 jscastro76

Thanks for your quick reply, i understand why you use mutationobserver for listening the changes...

i place code to listen change to my classes '.map-container'....

` ///////////// let observer = new MutationObserver(function (mutations) {

            mutations.forEach(function (mutation) {
                
                //console.log(mutation);
               
                if (mutation.attributeName === "class") {                        
                    $(mutation.target).trigger('classChange');
                }
            });
        });

        function observe(cssSelector) {
           
            //[jscastro] We add the observer for the map card that will change on maximize
            let o = observer.observe($(cssSelector)[0], {
                attributes: true
            });

            //[jscastro] on class change for the map card, we resize the map on a 200ms delay
            $(cssSelector).on('classChange', function () {

                window.setTimeout(function () {
                   console.log('change to map');
                }, 200);

            });

        }

        observe(".map-container");`

when i resizing my viewport i can see my debug... But the problem is that i can't see in my html view what parameter to check if i try to add map.current.resize(); i have a drop of framerate and it crash...

i use React do you think the problem should come from that....

I tried to add map.current.on('resize', function (e) {

console.log('resize'); //// work well

});

realy i should missanderstanding something

picpic1979 avatar Jul 15 '21 16:07 picpic1979

Do you have any update on this? were you able to identify what HTML component is changing the size?

jscastro76 avatar Aug 31 '21 10:08 jscastro76

I met this issue today. It seems like a bug, just modify one of the example page, like examples/10-stylechange.html, change defaultLights: true to realSunlight: true, then resize the browser window, and the 3D model will be distorting. I tried to force invoke map.resize() in window.onresize(), but it didn't work:

window.onresize = function() {
    console.log('resize');
    map.resize();
};

coocy avatar Oct 09 '21 11:10 coocy

I’ll check that out @coocy, thanks for the steps for repro

jscastro76 avatar Oct 09 '21 20:10 jscastro76

Setting defaultLights to true seemed to fix the problem for me, but now on resize the area that we can select the model by seems to move and distort. I had to revert back to 2.2.2 because 2.2.3 is where the bug appears. I'm using React.

EgorKrasno avatar Nov 28 '21 02:11 EgorKrasno