From 607e9375972bffc284b9ea5c5e13649e5dd61623 Mon Sep 17 00:00:00 2001 From: Tim Deubler Date: Fri, 8 Dec 2023 18:58:17 +0100 Subject: [PATCH] display(fixed): Glitches that may have appeared on the edges of previewed raster tiles have been resolved. Signed-off-by: Tim Deubler --- .../display/src/displays/webgl/GLRender.ts | 22 +++++++++++++------ .../displays/webgl/buffer/GeometryBuffer.ts | 2 ++ .../webgl/buffer/createImageBuffer.ts | 1 + .../src/displays/webgl/glsl/image_vertex.glsl | 9 ++++---- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/display/src/displays/webgl/GLRender.ts b/packages/display/src/displays/webgl/GLRender.ts index 8ccc23c4a..e0046fb72 100644 --- a/packages/display/src/displays/webgl/GLRender.ts +++ b/packages/display/src/displays/webgl/GLRender.ts @@ -98,6 +98,7 @@ export class GLRender implements BasicRender { r: false, g: false, b: false, a: false }; readonly vPMat: Float32Array; // projection matrix + readonly vPRasterMat: Float32Array; // pixel aligned projection matrix for raster data private readonly vMat: Float32Array; // view matrix private readonly invVPMat: Float32Array; // inverse projection matrix // the worldmatrix used by custom layers to project from absolute worldcoordinates [0-1] to screencoordinates @@ -175,6 +176,7 @@ export class GLRender implements BasicRender { }; this.vPMat = mat4.create(); + this.vPRasterMat = mat4.create(); this.vMat = mat4.create(); this.invVPMat = mat4.create(); this.screenMat = mat4.create(); @@ -438,9 +440,7 @@ export class GLRender implements BasicRender { // scale scale / groundRes ]); - mat4.translate(viewMatrix, viewMatrix, [-centerPixelX, -centerPixelY, 0]); - mat4.multiply(projectionMatrix, projectionMatrix, viewMatrix); invert(this.invVPMat, projectionMatrix); @@ -460,6 +460,14 @@ export class GLRender implements BasicRender { cameraWorld[2] = -1; transformMat4(cameraWorld, cameraWorld, this.invVPMat); + // pixel perfect matrix used for crisper raster graphics, icons/text/raster-tiles + // rounding in shader leads to precision issues and tiles edges become visible when the map is scaled. + const pixelPerfectMatrix = mat4.copy(this.vPRasterMat, projectionMatrix); + const worldCenterPixelX = worldCenterX * worldSize; + const worldCenterPixelY = worldCenterY * worldSize; + const dx = worldCenterPixelX - Math.round(worldCenterPixelX) + centerPixelX % 1; + const dy = worldCenterPixelY - Math.round(worldCenterPixelY) + centerPixelY % 1; + mat4.translate(pixelPerfectMatrix, pixelPerfectMatrix, [dx - Math.round(dx), dy - Math.round(dy), 0]); // used for debug only... // let s05 = mat4.clone(this.vPMat); @@ -643,7 +651,7 @@ export class GLRender implements BasicRender { const {sharedUniforms} = this; sharedUniforms.u_fixedView = this.fixedView; // must be set at render time sharedUniforms.u_scale = this.scale * dZoom; - sharedUniforms.u_matrix = pMat || this.vPMat; + sharedUniforms.u_matrix = pMat || (buffer.pixelPerfect ? this.vPRasterMat : this.vPMat); sharedUniforms.u_zMeterToPixel = this.zMeterToPixel / dZoom; const uses2PassAlpha = buffer.pass & PASS.POST_ALPHA; @@ -872,7 +880,7 @@ export class GLRender implements BasicRender { const scale = dWidth / sWidth; const px = dx / scale - sx; const py = dy / scale - sy; - const previewTransformMatrix = this.initPreviewMatrix(x, y, scale); + const previewTransformMatrix = this.initPreviewMatrix(x, y, scale, buffer.pixelPerfect); // if (buffer.scissor) { // this.initScissor(x + dx, y + dy, tileSize * scale, this.vPMat); // // this.initScissor(x - sx * scale, y - sy * scale, dWidth * scale, this.vPMat); @@ -886,15 +894,15 @@ export class GLRender implements BasicRender { } } - private initPreviewMatrix(tx: number, ty: number, s: number): Float32Array { - const {tilePreviewTransform, vPMat} = this; + private initPreviewMatrix(tx: number, ty: number, s: number, pixelPerfect?: boolean): Float32Array { + const {tilePreviewTransform} = this; const {m} = tilePreviewTransform; if ( tilePreviewTransform.tx != tx || tilePreviewTransform.ty != ty || tilePreviewTransform.s != s ) { - mat4.copy(m, vPMat); + mat4.copy(m, pixelPerfect ? this.vPRasterMat : this.vPMat); mat4.translate(m, m, [tx, ty, 0]); mat4.scale(m, m, [s, s, 1]); diff --git a/packages/display/src/displays/webgl/buffer/GeometryBuffer.ts b/packages/display/src/displays/webgl/buffer/GeometryBuffer.ts index 731653be4..d6fc19c2a 100644 --- a/packages/display/src/displays/webgl/buffer/GeometryBuffer.ts +++ b/packages/display/src/displays/webgl/buffer/GeometryBuffer.ts @@ -135,6 +135,8 @@ class GeometryBuffer { instances: number = 0; // id of the program to render the buffer progId: string; + // If set to true, the buffer should render "pixel-perfect" to ensure sharp, precise raster graphics. + pixelPerfect?: boolean = false; private _cullFace: number = 0; diff --git a/packages/display/src/displays/webgl/buffer/createImageBuffer.ts b/packages/display/src/displays/webgl/buffer/createImageBuffer.ts index 29cc12767..995ecfc56 100644 --- a/packages/display/src/displays/webgl/buffer/createImageBuffer.ts +++ b/packages/display/src/displays/webgl/buffer/createImageBuffer.ts @@ -66,6 +66,7 @@ const createImageBuffer = (img: Image, gl: WebGLRenderingContext, size: number, tileBuffer.clip = true; tileBuffer.blend = alpha; tileBuffer.pass = alpha ? PASS.ALPHA : PASS.OPAQUE; + tileBuffer.pixelPerfect = true; tileBuffer.cullFace(FRONT); diff --git a/packages/display/src/displays/webgl/glsl/image_vertex.glsl b/packages/display/src/displays/webgl/glsl/image_vertex.glsl index 187008e13..d6a026a72 100644 --- a/packages/display/src/displays/webgl/glsl/image_vertex.glsl +++ b/packages/display/src/displays/webgl/glsl/image_vertex.glsl @@ -7,12 +7,13 @@ uniform highp mat4 u_matrix; uniform highp vec2 u_topLeft; uniform highp vec2 u_resolution; uniform float u_tileScale; -//uniform bool u_snapGrid; +//uniform bool u_fixedView; varying vec2 v_textureCoord; +uniform float u_scale; void main(void){ v_textureCoord = a_textureCoord; - vec4 position = u_matrix * vec4( u_topLeft + a_position * u_tileScale, 0.0, 1.0 ); - gl_Position = snapToScreenPixel(position, u_resolution); -// gl_Position = u_snapGrid ? snapToScreenPixel(position, u_resolution) : position; + highp vec4 position = u_matrix * vec4( u_topLeft + a_position * u_tileScale, 0.0, 1.0 ); + gl_Position = position; +// gl_Position = u_fixedView ? snapToScreenPixel(position, u_resolution) : position; }