Search code examples
openstreetmaptexture-mappingmap-projectionsuv-mappingmercator

How to correctly find UV on sphere


I have a sphere and a texture for it. enter image description here

Texture consist of 16 tiles of zoom = 2 from OSM. Tile size is 256x256.

At top and bottom I added space to cover area in ranges [90, 85.0511] and [-85.0511, -90], proportionally. So texture size was 1024x1083.

I also tried texture without these two spaces, its size was 1024x1024 (map tiles only).

The problem is that after UV mapping on Y-axis objects are smaller on equator and bigger on poles.

enter image description here

There are two types of formulas

u = (lon + 180) / 360; // lon = [-180, 180]
v = (lat + 90) / 180; // lat = [-85.0511, 85.0511]
----
u = Math.atan2(z, x) / (2 * Math.PI) + 0.5; // x, y, z are vertex coordinates
v = Math.asin(y) / Math.PI + 0.5;

I tried all 8 variations: two textures, two u-formulas and two v-formulas.

The result is like on image above, or worse.

What am I doing wrong? Is it about texture, or UV-formulas, or something else?

P.S.: for poles (vertices in lat range = [-90, -85.0511], [85.0511, 90]) in fragment shader I don't use color from texture, but just solid color


Solution

  • OSM uses the Web Mercator projection. See also on OSM wiki.

    The conversion from world (x,y,z) to texture (u,v) coordinates would be:

    lon = atan2(y, x)
    lat = atan2(z, sqrt(x*x+y*y))
    u = (lon + pi)/(2*pi)
    v = (log(tan(lat/2 + pi/4)) + pi)/(2*pi)
    

    (I assume that z points north like in WGS-84 and all coordinates are right-handed.)

    This projection doesn't cover the entire sphere: as the latitude approaches the poles, the v coordinate blows up to infinity. Therefore extending the map to the north or south direction is not going to be helpful.

    Instead keep the original square 1024x1024 texture and render a texture mapped sphere capped at the ±85.051129° latitute (that's where v = 0,1) using the above coordinate mapping.

    Alternatively (and this is more in-line with Web Mercator spirit), render each tile regular in the UV coordinates, and calculate the XYZ coordinates by reversing the above transformation.