将墨卡托投影转换为等距柱状投影的着色器?

Shader that transforms a mercator projection to equirectangular?

我正在尝试在 Unity 中使用 mercator projection texture as a source and converting it to an equirectangular projection texture.

制作着色器

输入示例:

输出示例:

This example does the opposite with an equirectangular as source.

如果你看上面例子的来源:

 // mercator
 float latClamped = clamp(lat, -1.4835298641951802, 1.4835298641951802);
 float yMerc = log(tan(PI / 4.0 + latClamped / 2.0)) / PI2;
 float xMerc = xEqui / 2.0;
 vec4 mercatorPos = vec4(xMerc, yMerc, 0.0, 1.0);

任何人都可以帮助扭转这种情况,以便我能够从墨卡托贴图作为源转到等距柱状贴图(或者更好,azimuthal)。

正在寻找一种从 x/y 到经度 (x)/纬度 (y) 并返回的 2D 纹理变形方法。

感谢您的意见。

如果要输出等距柱状投影,需要将等距柱状坐标转换为墨卡托坐标,然后在这些坐标处对墨卡托投影进行采样。

这是它在来自 uvs 的片段着色器中的样子:

//uv to equirectangular
float lat = (uv.x) * 2 * PI;    // from 0 to 2PI
float lon = (uv.y - .5f) * PI;  // from -PI to PI

// equirectangular to mercator
float x = lat;
float y = log(tan(PI / 4. + lon / 2.));

// bring x,y into [0,1] range
x = x / (2*PI);
y = (y+PI) / (2*PI);

// sample mercator projection
fixed4 col = tex2D(_MainTex, float2(x,y));

同样的事情也适用于方位角投影:您可以从方位角坐标 -> 等距柱状 -> 墨卡托投影并对图像进行采样。或者你可以找到一个公式直接从方位角 - >墨卡托。 wiki pages have a bunch of formulas to go back and forth between projections.

Here is a full shader to play around with. Input is a mercator projection and outputs a equirectangular or azimuthal projection (choose from the dropdown menu)

Shader "Unlit/NewUnlitShader 1"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        [Enum(Equirectangular,0,Azimuthal,1)]
        _Azimuthal("Projection", float) = 0

    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag           

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;                
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Azimuthal;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
#define PI 3.141592653589793238462f
#define PI2 6.283185307179586476924f

            float2 uvToEquirectangular(float2 uv) {
                float lat = (uv.x) * PI2;   // from 0 to 2PI
                float lon = (uv.y - .5f) * PI;  // from -PI to PI
                return float2(lat, lon);
            }

            float2 uvAsAzimuthalToEquirectangular(float2 uv) {                  
                float2 coord = (uv - .5) * 4; 

                float radius = length(coord);
                float angle = atan2(coord.y, coord.x) + PI;

                //formula from https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection
                float lat = angle;
                float lon = 2 * acos(radius / 2.) - PI / 2;
                return float2(lat, lon);
            }           

            fixed4 frag(v2f i) : SV_Target
            {
                // get equirectangular coordinates
                float2 coord = _Azimuthal ? uvAsAzimuthalToEquirectangular(i.uv) : uvToEquirectangular(i.uv);

                // equirectangular to mercator
                float x = coord.x;
                float y = log(tan(PI / 4. + coord.y / 2.));
                // brin x,y into [0,1] range
                x = x / PI2;
                y = (y + PI) / PI2;                 

                fixed4 col = tex2D(_MainTex, float2(x,y));

                // just to make it look nicer
                col = _Azimuthal && length(i.uv*2-1) > 1 ? 1 : col;

                return col;
            }
            ENDCG
        }
    }
}