Шейдер, который преобразует проекцию Меркатора в эквикт angular? - PullRequest
2 голосов
/ 25 января 2020

Я пытаюсь создать шейдер в Unity, используя текстуру проекции меркатора в качестве источника и преобразовывая ее в эквалайзер angular текстуру проекции .

Пример ввода:

enter image description here

enter image description here

Пример вывода:

enter image description here

enter image description here

В этом примере выполняется обратное с angular в качестве источника .

Если вы посмотрите на источник приведенного выше примера:

 // 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);

Может кто-нибудь помогите изменить это так, чтобы я мог go из карты меркатора в качестве источника для эквалайзера angular (или даже лучше, азимутальный ).

В поисках пути к делать деформации 2D текстуры, переходя от x / y к долготе (x) / широте (y) и обратно.

Я ценю ваш вклад.

1 Ответ

1 голос
/ 26 января 2020

Если вы хотите вывести эквиктивную angular проекцию, вам необходимо преобразовать эквинальные angular координаты в координаты меркатора, а затем произвести выборку проекции меркатора по этим координатам. Вот как это будет выглядеть в фрагментном шейдере от 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));

То же самое относится и к азимутальной проекции: вы можете go из азимутальных координат -> равных angular -> меркатора и образец изображения. Или вы можете найти формулу go прямо из азимутальной -> меркатора. Страницы wiki имеют набор формул для go туда-сюда между проекциями. Вот полный шейдер, с которым можно поиграть. Ввод является проекцией Меркатора и выводит прямую angular или азимутальную проекцию (выберите из выпадающего меню) enter image description here

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
        }
    }
}
...