130 lines
4.9 KiB
GLSL
130 lines
4.9 KiB
GLSL
#version 300 es
|
|
|
|
layout(location = 0) in vec2 a_pos;
|
|
layout(location = 1) in vec2 a_tex_coord;
|
|
|
|
const float PI = 3.141592653589793;
|
|
uniform mat4 u_projection_matrix;
|
|
#define GLOBE_RADIUS 6371008.8
|
|
uniform highp vec4 u_projection_tile_mercator_coords;
|
|
uniform highp vec4 u_projection_clipping_plane;
|
|
uniform highp float u_projection_transition;
|
|
uniform mat4 u_projection_fallback_matrix;
|
|
|
|
vec3 globeRotateVector(vec3 vec,vec2 angles) {
|
|
vec3 axisRight=vec3(vec.z,0.0,-vec.x);
|
|
vec3 axisUp=cross(axisRight,vec);
|
|
axisRight=normalize(axisRight);
|
|
axisUp=normalize(axisUp);
|
|
vec2 t=tan(angles);
|
|
return normalize(vec+axisRight*t.x+axisUp*t.y);
|
|
}
|
|
|
|
mat3 globeGetRotationMatrix(vec3 spherePos) {
|
|
vec3 axisRight=vec3(spherePos.z,0.0,-spherePos.x);
|
|
vec3 axisDown=cross(axisRight,spherePos);
|
|
axisRight=normalize(axisRight);
|
|
axisDown=normalize(axisDown);
|
|
return mat3(axisRight,axisDown,spherePos);
|
|
}
|
|
|
|
float circumferenceRatioAtTileY(float tileY) {
|
|
float mercator_pos_y = u_projection_tile_mercator_coords.y + u_projection_tile_mercator_coords.w*tileY;
|
|
float spherical_y = 2.0*atan(exp(PI-(mercator_pos_y*PI*2.0))) - PI*0.5;return cos(spherical_y);
|
|
}
|
|
|
|
float projectLineThickness(float tileY) {
|
|
float thickness=1.0/circumferenceRatioAtTileY(tileY);
|
|
if (u_projection_transition < 0.999) {
|
|
return mix(1.0,thickness,u_projection_transition);
|
|
} else {
|
|
return thickness;
|
|
}
|
|
}
|
|
|
|
vec3 projectToSphere(vec2 translatedPos,vec2 rawPos) {
|
|
vec2 mercator_pos = u_projection_tile_mercator_coords.xy+u_projection_tile_mercator_coords.zw*translatedPos;
|
|
vec2 spherical;
|
|
spherical.x=mercator_pos.x*PI*2.0+PI;
|
|
spherical.y=2.0*atan(exp(PI-(mercator_pos.y*PI*2.0)))-PI*0.5;
|
|
float len=cos(spherical.y);
|
|
vec3 pos=vec3(sin(spherical.x)*len,sin(spherical.y),cos(spherical.x)*len);
|
|
if (rawPos.y <-32767.5) {
|
|
pos = vec3(0.0,1.0,0.0);
|
|
}
|
|
if (rawPos.y > 32766.5) {
|
|
pos=vec3(0.0,-1.0,0.0);
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
vec3 projectToSphere(vec2 posInTile) {
|
|
return projectToSphere(posInTile,vec2(0.0,0.0));
|
|
}
|
|
|
|
// 计算纬度和经度(以角度为单位)
|
|
vec2 computeLatLon(vec2 posInTile) {
|
|
vec2 mercator_pos = u_projection_tile_mercator_coords.xy + u_projection_tile_mercator_coords.zw * posInTile;
|
|
vec2 spherical;
|
|
spherical.x = mercator_pos.x * PI * 2.0 + PI; // 经度(弧度)
|
|
spherical.y = 2.0 * atan(exp(PI - (mercator_pos.y * PI * 2.0))) - PI * 0.5; // 纬度(弧度)
|
|
|
|
// 转换为角度
|
|
vec2 lonlat_degrees;
|
|
lonlat_degrees.x = spherical.x * 180.0 / PI; // 经度(角度)
|
|
lonlat_degrees.y = spherical.y * 180.0 / PI; // 纬度(角度)
|
|
|
|
// 确保经度在0-360范围内
|
|
lonlat_degrees.x = mod(lonlat_degrees.x + 360.0, 360.0);
|
|
|
|
return lonlat_degrees;
|
|
}
|
|
|
|
float globeComputeClippingZ(vec3 spherePos) {
|
|
return (1.0-(dot(spherePos,u_projection_clipping_plane.xyz)+u_projection_clipping_plane.w));
|
|
}
|
|
|
|
vec4 interpolateProjection(vec2 posInTile,vec3 spherePos,float elevation) {
|
|
vec3 elevatedPos=spherePos*(1.0+elevation/GLOBE_RADIUS);
|
|
vec4 globePosition=u_projection_matrix*vec4(elevatedPos,1.0);
|
|
globePosition.z=globeComputeClippingZ(elevatedPos)*globePosition.w;
|
|
|
|
if (u_projection_transition > 0.999) {return globePosition;}
|
|
|
|
vec4 flatPosition=u_projection_fallback_matrix*vec4(posInTile,elevation,1.0);
|
|
const float z_globeness_threshold=0.2;
|
|
|
|
vec4 result=globePosition;result.z=mix(0.0,globePosition.z,clamp((u_projection_transition-z_globeness_threshold)/(1.0-z_globeness_threshold),0.0,1.0));result.xyw=mix(flatPosition.xyw,globePosition.xyw,u_projection_transition);if ((posInTile.y <-32767.5) || (posInTile.y > 32766.5)) {result=globePosition;const float poles_hidden_anim_percentage=0.02;result.z=mix(globePosition.z,100.0,pow(max((1.0-u_projection_transition)/poles_hidden_anim_percentage,0.0),8.0));}return result;}vec4 interpolateProjectionFor3D(vec2 posInTile,vec3 spherePos,float elevation) {vec3 elevatedPos=spherePos*(1.0+elevation/GLOBE_RADIUS);vec4 globePosition=u_projection_matrix*vec4(elevatedPos,1.0);
|
|
|
|
if (u_projection_transition > 0.999) {return globePosition;}
|
|
|
|
vec4 fallbackPosition=u_projection_fallback_matrix*vec4(posInTile,elevation,1.0);
|
|
return mix(fallbackPosition,globePosition,u_projection_transition);
|
|
}
|
|
|
|
vec4 projectTile(vec2 posInTile) {
|
|
return interpolateProjection(posInTile,projectToSphere(posInTile),0.0);
|
|
}
|
|
|
|
vec4 projectTile(vec2 posInTile,vec2 rawPos) {
|
|
return interpolateProjection(posInTile,projectToSphere(posInTile,rawPos),0.0);
|
|
}
|
|
|
|
vec4 projectTileWithElevation(vec2 posInTile,float elevation) {
|
|
return interpolateProjection(posInTile,projectToSphere(posInTile),elevation);
|
|
}
|
|
|
|
vec4 projectTileFor3D(vec2 posInTile,float elevation) {
|
|
vec3 spherePos=projectToSphere(posInTile,posInTile);
|
|
return interpolateProjectionFor3D(posInTile,spherePos,elevation);
|
|
}
|
|
|
|
#define GLOBE
|
|
|
|
out vec2 lonlat;
|
|
|
|
void main() {
|
|
gl_Position = projectTile(a_pos);
|
|
lonlat = computeLatLon(a_pos);
|
|
} |