mapbox / mapbox-unity-sdk

Mapbox Unity SDK - https://www.mapbox.com/unity/
Other
721 stars 214 forks source link

Mapbox VR scale is wrong #1378

Open asmccormick opened 5 years ago

asmccormick commented 5 years ago

I'm trying to use Mapbox to create an accurate environment for VR. For example, if a real skyscraper in NYC is 100m tall in real life, it should be 100m tall in VR. I've tried adjusting the zoom scale and changing World Scale to Custom, but no combination of these will make the buildings appear at their actual height.

In hopes of finding a Mapbox-to-Realworld ratio, I gathered some data points. building heights and ratios

Here's my methodology:

From these 7 data points, I calculated an average ratio of 6.12. However, I'm not terribly confident in the accuracy of my method, nor do I have any idea what this number signifies.

Does anyone know what 6.12 refers to? Does anyone know of a precise zoom level where Mapbox creates buildings to their actual scale?

brnkhy commented 5 years ago

Hey @asmccormick! Great catch and thanks for all detailed data. height precision isn't easy and to be honest not something used/required regularly so I guess we looked over this. After a quick inspection, I think I found something.

if you check MapScalingAtWorldScaleStrategy class you'll find this method. original

public void SetUpScaling(AbstractMap map)
{
    var scaleFactor = Mathf.Pow(2, (map.AbsoluteZoom - map.InitialZoom));
    map.SetWorldRelativeScale(scaleFactor * Mathf.Cos(Mathf.Deg2Rad * (float)map.CenterLatitudeLongitude.x));
}

That calculation starting with mathf.Cos is actually a fix for the latitude in fixed size tiles since forcing tiles down to a certain size is a little more complex in y axis because of the mercator tile sizes (they shrink as latitude goes higher/lower). But that is unnecessary in world scale because in that mode we're not scaling tiles at all! So I just commented that out and tested with Columbia Tower which came very close to 286m using the exact method you used.

changed

public void SetUpScaling(AbstractMap map)
{
    var scaleFactor = Mathf.Pow(2, (map.AbsoluteZoom - map.InitialZoom));
    map.SetWorldRelativeScale(scaleFactor); 
}

So if you can change that line as shown above and test in WorldScale mode again, I think you will get much better results. I'm not creating a branch and PR as I would like to test a little bit more myself as well, but theoretically it makes sense and we probably just looked over the fact that it's not necessary in world scale mode while writing that class.

Hope that helps!

brnkhy commented 5 years ago

I couldn't resists so I created a PR; https://github.com/mapbox/mapbox-unity-sdk/pull/1384 we can test and talk there as well anyway. Thanks a lot again @asmccormick

abhishektrip commented 5 years ago

@asmccormick Thanks for the detailed analysis and awesome ticket 🎉

asmccormick commented 4 years ago

Simplest fix is to set AbstractMap to World Scale and zoom to 16x. Then set y-scale of map gameObject like this

void FixMapScale ()
    {
        float verticalScale = 1 / Mathf.Cos(Mathf.Deg2Rad * (float)AbstractMapScript.CenterLatitudeLongitude.x);
        MapTransform.localScale = new Vector3(1f, verticalScale, 1f);
    }

Note that changing the scale of a Unity object may create some strange behaviors from physics, colldiers, raycasting, etc etc.

supergra commented 4 years ago

Confirmed, this fixes elevation for my application as well, across a range of latitudes.

Note that if you are also calling AbstractMap.QueryElevationInUnityUnitsAt(), then you need to multiply the result by the same verticalScale factor computed above, even if you scale the map transform, as done above.

However, if you scale the map transform and call AbstractMap.GeoToWorldPosition() with the queryHeight parameter, then don't scale the result, it already includes it, since it uses the Unity tile transform, and so picks up the map scale.

supergra commented 4 years ago

Really would love to see https://github.com/mapbox/mapbox-unity-sdk/pull/1384 fixed and pushed!

Markovicho commented 4 years ago

I can confirm that changing the mentioned line in MapScalingAtWorldScaleStrategy.SetUpScaling will fix this issue like you can see in the pictures below:

Test with 200m Cube (respecting WorldRelativeScale) vs. 200m real world tower

Before image

After image

Look's legit now :-)