在2D游戏中实现地球仪的旋转

代码和说明
1. 固定地轴Shader
real4 frag(v2f i) : SV_Target
{
// 将UV原点换到图片中央
float2 uv = i.uv - 0.5;
// 根据勾股定理计算 z = sqrt( r*r - (x*x + y*y ))
float3 pos = float3(uv.x, uv.y, sqrt(0.25 - (uv.x * uv.x + uv.y * uv.y)));
// 将得到的点坐标转换到球面坐标系,得到phi角度并转到(-1,1)
float p = atan2(pos.x, pos.z) * INV_PI;
// 结合_Time.y 和 输入参数转动速度
float2 suv = float2(frac(p + (_Speed * _Time.y)), i.uv.y);
// 使用distance确定出圆的范围,结合smoothstep获得平滑的圆边缘
real4 col = tex2D(_MainTex, suv) * smoothstep(0.51, 0.49, distance(i.uv, 0.5));
return col;
}
2.地轴可旋转Shader
Shader说明如下:
real4 frag(v2f i) : SV_Target
{
// 球的半径为UV范围的一半
half r = 0.5;
// 半径的平方
half rr = r * r;
// 移动UV原点到画布中心
float2 uv = i.uv - r;
// 将角度转为弧度
half angle = radians(_Angle);
float x = uv.x;
float xx = x * x;
// 根据勾股定理算出当前点在笛卡尔坐标相对x轴的距离
float le = sqrt(rr - xx);
// 计算当前点所在YZ平面确定的圆上旋转角度
float angleY = asin(uv.y/le);
// 当前旋转角度加上给定的地轴旋转角度就是当前点的最终角度
// 根据该角度计算当前点的最终坐标
float y = sin(angleY + angle) * le;
float z = sqrt(rr - (xx + y * y));
// 当前点如果位于背面,因为地轴旋转导致显示出现的情况,则需要将z值反转
if(HALF_PI - angleY < angle)
{
z = -z;
}
// 将最终坐标转成球面坐标系,然后映射到UV的范围
float p = atan2(x, z) * INV_PI * 0.5;
float t = (asin(y / r) * INV_PI + .5);
// 最终经过球面映射的UV
float2 suv = float2(frac(p + (_Speed * _Time.y)), t);
real4 col = tex2D(_MainTex, suv) * smoothstep(0.51, 0.49, distance(i.uv, 0.5));
return col;
}