diff --git a/packages/core/src/services/coordinate/CoordinateSystemService.ts b/packages/core/src/services/coordinate/CoordinateSystemService.ts index 45f9e8d5ff..ac059e4975 100644 --- a/packages/core/src/services/coordinate/CoordinateSystemService.ts +++ b/packages/core/src/services/coordinate/CoordinateSystemService.ts @@ -26,15 +26,16 @@ export default class CoordinateSystemService implements ICoordinateSystemService private viewportCenter: [number, number]; /** - * 屏幕中心点的最终投影结果,在 CPU 侧计算后传入 Shader - * @see https://zhuanlan.zhihu.com/p/57469121 + * 屏幕中心点的 fp64 低精度部分,用于高精度坐标偏移计算 + * fp64LowPart(x) = x - Math.fround(x) */ - private viewportCenterProjection: [number, number, number, number]; + private viewportCenterLow: [number, number] = [0, 0]; /** - * 像素单位 -> 经纬度 [x, y, z] + * 屏幕中心点的最终投影结果,在 CPU 侧计算后传入 Shader + * @see https://zhuanlan.zhihu.com/p/57469121 */ - private pixelsPerDegree: [number, number, number]; + private viewportCenterProjection: [number, number, number, number]; /** * 像素单位 -> 经纬度 [lng, lat] 使用泰勒级数展开 @@ -48,6 +49,11 @@ export default class CoordinateSystemService implements ICoordinateSystemService */ private pixelsPerMeter: [number, number, number]; + /** + * 像素单位 -> 经纬度 [x, y, z] + */ + private pixelsPerDegree: [number, number, number]; + /** * 重新计算当前坐标系参数 * TODO: 使用 memoize 缓存参数以及计算结果 @@ -66,6 +72,11 @@ export default class CoordinateSystemService implements ICoordinateSystemService zoom, }); this.viewportCenter = center; + // 计算 fp64 低精度部分,用于高精度坐标偏移:fp64LowPart(x) = x - Math.fround(x) + this.viewportCenterLow = [ + center[0] - Math.fround(center[0]), + center[1] - Math.fround(center[1]), + ]; this.viewportCenterProjection = [0, 0, 0, 0]; this.pixelsPerMeter = pixelsPerMeter; this.pixelsPerDegree = pixelsPerDegree; @@ -102,6 +113,10 @@ export default class CoordinateSystemService implements ICoordinateSystemService return this.viewportCenterProjection; } + public getViewportCenterLow(): [number, number] { + return this.viewportCenterLow; + } + public getPixelsPerDegree(): [number, number, number] { return this.pixelsPerDegree; } diff --git a/packages/core/src/services/coordinate/ICoordinateSystemService.ts b/packages/core/src/services/coordinate/ICoordinateSystemService.ts index 2edceb023a..52ddc4467b 100644 --- a/packages/core/src/services/coordinate/ICoordinateSystemService.ts +++ b/packages/core/src/services/coordinate/ICoordinateSystemService.ts @@ -21,6 +21,7 @@ export const CoordinateUniform = { CoordinateSystem: 'u_CoordinateSystem', ViewportCenter: 'u_ViewportCenter', ViewportCenterProjection: 'u_ViewportCenterProjection', + ViewportCenterLow: 'u_ViewportCenterLow', PixelsPerDegree: 'u_PixelsPerDegree', PixelsPerDegree2: 'u_PixelsPerDegree2', PixelsPerMeter: 'u_PixelsPerMeter', @@ -35,6 +36,7 @@ export interface ICoordinateSystemService { getViewportCenter(): [number, number]; setViewportCenter(center: [number, number]): void; getViewportCenterProjection(): [number, number, number, number]; + getViewportCenterLow(): [number, number]; getPixelsPerDegree(): [number, number, number]; getPixelsPerDegree2(): [number, number, number]; getPixelsPerMeter(): [number, number, number]; diff --git a/packages/core/src/shaders/projection.glsl b/packages/core/src/shaders/projection.glsl index 90f69519b5..1b9d51192b 100644 --- a/packages/core/src/shaders/projection.glsl +++ b/packages/core/src/shaders/projection.glsl @@ -84,10 +84,11 @@ vec4 project_position(vec4 position, vec2 position64xyLow) { vec2 center = u_ViewportCenter; float X = absolutePosition.x - center.x; float Y = absolutePosition.y - center.y; + // 减去中心点的低精度部分,实现全双精度坐标计算,解决高缩放级别下坐标偏移问题 return project_offset( vec4( - X + absolutePosition64xyLow.x, - Y + absolutePosition64xyLow.y, + X + absolutePosition64xyLow.x - u_ViewportCenterLow.x, + Y + absolutePosition64xyLow.y - u_ViewportCenterLow.y, absolutePosition.z, absolutePosition.w ) diff --git a/packages/core/src/shaders/scene_uniforms.glsl b/packages/core/src/shaders/scene_uniforms.glsl index 06a4cc8462..5e9fe0c810 100644 --- a/packages/core/src/shaders/scene_uniforms.glsl +++ b/packages/core/src/shaders/scene_uniforms.glsl @@ -17,4 +17,5 @@ layout(std140) uniform SceneUniforms { float u_FocalDistance; vec2 u_RelativeOrigin; float u_Reserved3; + vec2 u_ViewportCenterLow; }; diff --git a/packages/layers/src/plugins/ShaderUniformPlugin.ts b/packages/layers/src/plugins/ShaderUniformPlugin.ts index cb2e152871..502d1eec2f 100644 --- a/packages/layers/src/plugins/ShaderUniformPlugin.ts +++ b/packages/layers/src/plugins/ShaderUniformPlugin.ts @@ -118,6 +118,7 @@ export default class ShaderUniformPlugin implements ILayerPlugin { const u_ViewportSize = [width, height]; const u_FocalDistance = this.cameraService.getFocalDistance(); const u_RelativeOrigin = offset && offset.length >= 2 ? [offset[0], offset[1]] : [0, 0]; + const u_ViewportCenterLow = this.coordinateSystemService.getViewportCenterLow(); const data: number[] = [ ...u_ViewMatrix, // 16 @@ -137,7 +138,8 @@ export default class ShaderUniformPlugin implements ILayerPlugin { ...u_ViewportSize, // 4 u_FocalDistance, // 1 ...u_RelativeOrigin, // 2 - 0, // padding + 0, // padding (u_Reserved3) + ...u_ViewportCenterLow, // 2 ]; return { @@ -155,6 +157,7 @@ export default class ShaderUniformPlugin implements ILayerPlugin { [CoordinateUniform.CoordinateSystem]: u_CoordinateSystem, [CoordinateUniform.ViewportCenter]: u_ViewportCenter, [CoordinateUniform.ViewportCenterProjection]: u_ViewportCenterProjection, + [CoordinateUniform.ViewportCenterLow]: u_ViewportCenterLow, [CoordinateUniform.PixelsPerDegree]: u_PixelsPerDegree, [CoordinateUniform.PixelsPerDegree2]: u_PixelsPerDegree2, [CoordinateUniform.PixelsPerMeter]: u_PixelsPerMeter,