unity3d - 将墨卡托投影转换为等矩形的着色器?
问题描述
我正在尝试在 Unity 中制作一个着色器,将墨卡托投影纹理作为源并将其转换为等角投影纹理。
输入示例:
输出示例:
此示例使用 equirectangular 作为 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);
任何人都可以帮助扭转这一点,这样我就可以从墨卡托地图作为来源到等距矩形(甚至更好,方位角)。
寻找一种方法来进行从 x/y 到经度(x)/纬度(y)并返回的 2D 纹理变形。
感谢您的意见。
解决方案
如果要输出 equirectangular 投影,则需要将 equirectangular 坐标转换为墨卡托坐标,然后在这些坐标处对墨卡托投影进行采样。
这是它在 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));
同样的事情也适用于方位角投影:您可以从方位角坐标 -> equirectangular -> mercator 对图像进行采样。或者你可以找到一个公式直接从方位角 -> 墨卡托。wiki页面有一堆公式可以在投影之间来回切换。
这是一个完整的着色器。输入是墨卡托投影并输出等距或方位角投影(从下拉菜单中选择)
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
}
}
}
推荐阅读
- r - 如何更改 R 中 2 个栅格图层的分辨率?
- reactjs - 反应材料ui的数据网格:可编辑列不起作用
- json - Jmeter提取具有包含和不包含条件的Json响应
- django - 从下拉菜单 django admin 中删除已注册的 celery 任务
- python - 将 TensorFlow Python 转换为 C# XOR 示例引发异常
- ios - 未能获得匹配的快照:失去与应用程序的连接
- r - 怎么可能画
- oracle-apex - Oracle Apex:Last_updated_by
- c++ - UE4 Gameplay Ability Systems - 触发断点错误
- ruby-on-rails - Rails 6 - 524288 通知观察者不足以启动服务器和控制台