uv-mapping

HEALPix with texture UV mapping


I found an implementation of the HEALpix algorithm this is the dokumentation And the output looks very nice.

The following images show the latitude / longitude conversion to HEALpix areas. The x-axe goes from 0 to 2 * pi. The y-axe goes from 0 to pi. The grey color represents the HEALpix pixel encoded in grey.

Nside = 1 enter image description here

Nside = 2 enter image description here

Nside = 4 enter image description here

Nside = 8 enter image description here

The different grey values are the IDs for the texture I have to use. That means, that each HEALpix pixel represents one texture. The missing part is the UV mapping within each of the HEALpix pixels like shown below:

nSide = 1 with UV mapping enter image description here

Right now I am using the function:

void ang2pix_ring( const long nside, double theta, double phi, long *ipix)

Which gives me the correct texture ID. But I've no idea how to calculate the UV mapping for each HEALpix pixel. Is there a way to calculate all four corners in lat/lon coordinates of a HEALpix pixel? Or even better a direct calculation to the UV coordinates?

BTW: I am using the RING scheme. But if the NESTED scheme is simpler to calculate I also would change to that.


Solution

  • After a lot of research I came to a solution for this problem:

    First of all, I've changed the scheme to NESTED. With the NESTED scheme and a very high nSide value (8192), the returned value from the

    void ang2pix_ring( const long nside, double theta, double phi, long *ipix)
    

    function gives back a long value where the UV coordinates can be read out in the following way:

    Bit 26 till 30 represents the level 0 (only the 12 HEALPix pixels).

    By using higher levels, the Bits from 30 till 26 - (level * 2) represents the HEALPix pixels.

    The leftover 26 - (level * 2) - 1 till bit 1 encode the UV texture-coordinates in the following way:

    Each second odd bit shrink together represents the U coordinate and the even once represents the V coordinate. To normalize these UV-coordinates the responding shrinked values need to be divided by the value of pow(2, (26 - level * 2) / 2).

    Code says more than 1000 words:

    unsigned long ignoreEverySecondBit(unsigned long value, bool odd, unsigned int countBits)
    {
        unsigned long result = 0;
        unsigned long mask = odd == true ? 0b1 : 0b10;
        countBits = countBits / 2;
        for (int i = 0; i < countBits; ++i)
        {
            if ((value & mask) != 0)
            {
                result += std::pow(2, i);
            }
            mask = mask << 2;
        }
    
        return result;
    }
    
    
    //calculate the HEALPix values:
    latLonToHealPixNESTED(nSide, theta, phi, &pix);
    
    result.level = level;
    result.texture = pix >> (26 - level * 2);
    result.u = static_cast<float>(ignoreEverySecondBit(pix, true, 26 - level * 2));
    result.v = static_cast<float>(ignoreEverySecondBit(pix, false, 26 - level * 2));
    
    result.u = result.u / pow(2, (26 - level * 2) / 2);
    result.v = result.v / pow(2, (26 - level * 2) / 2);
    

    And of cause a few images to show the results. The blue value represents the textureID, the red value represents the U-coordinate and the green value represents the V-coordinate:

    Level 0 enter image description here

    Level 1 enter image description here

    Level 2 enter image description here

    Level 3 enter image description here

    Level 4 enter image description here

    I hope this solution will help others too.