Right-side-up text: flip UNPACK flag + swap canvas axes

UNPACK_FLIP_Y_WEBGL=true was correct for screen orientation but the
shader's rotated-frame math expected it false. To get both right:

- Re-enable UNPACK_FLIP_Y_WEBGL=true so canvas top maps to texture
  V=1 (screen top). Text now reads right-side up.
- Invert the drawing axes: canvasY = (-lng + halfLong + 0.5)*TILE_SIZE
  so lng=+12 (corridor front, ahead) lands at small canvas Y, which
  after upload ends up at texture V=1, i.e. at screen top.
  Same inversion for perp.
- Shader's gUv.y = rotated.x / uGroundSize.y + 0.5 is unchanged:
  for offset.z=+12 (north) it samples V=0.98 -> texture row 6271
  -> canvas row 128 (the new top-of-corridor row) -> lng=+12. Correct.

Effect: N labels read upright, image orientation matches world
directions, and corridor scrolls in the visible flight direction.
This commit is contained in:
Richard Zink committed 2026-10-08 06:51:46 +02:00
1 parent a05951efbd
commit 2fd394a865
1 file changed
+8 -3
+8 -3
View File
@@ -328,8 +328,13 @@ function drawTileAt(lng, perp, dx, dz, centerTileX, centerTileY) {
// (vertical) and perp along canvas X (horizontal). This way the // (vertical) and perp along canvas X (horizontal). This way the
// corridor's long axis (flight direction +Z) appears as a vertical // corridor's long axis (flight direction +Z) appears as a vertical
// strip on canvas, matching the way depth maps on screen. // strip on canvas, matching the way depth maps on screen.
var canvasX = (perp + halfPerp + 0.5) * GROUND_TILE_SIZE; // With UNPACK_FLIP_Y_WEBGL=true, canvas top -> texture V=1 (screen top).
var canvasY = (lng + halfLong + 0.5) * GROUND_TILE_SIZE; // We want lng=+12 (corridor north/front, ahead of camera) at screen top.
// So canvasY is inverted: small Y = high lng (north).
// Same idea for perp: world east (dx > 0) should be on screen right,
// so canvasX is also inverted: large X = perp < 0 = dx > 0 = east.
var canvasX = (-perp + halfPerp + 0.5) * GROUND_TILE_SIZE;
var canvasY = (-lng + halfLong + 0.5) * GROUND_TILE_SIZE;
if (canvasX < 0 || canvasX >= groundCanvas.width || canvasY < 0 || canvasY >= groundCanvas.height) { if (canvasX < 0 || canvasX >= groundCanvas.width || canvasY < 0 || canvasY >= groundCanvas.height) {
return Promise.resolve(false); return Promise.resolve(false);
} }
@@ -447,7 +452,7 @@ function initGroundSystem(glCtx) {
groundCtx.fillRect(0, 0, groundCanvas.width, groundCanvas.height); groundCtx.fillRect(0, 0, groundCanvas.width, groundCanvas.height);
groundTexture = groundGl.createTexture(); groundTexture = groundGl.createTexture();
groundGl.bindTexture(groundGl.TEXTURE_2D, groundTexture); groundGl.bindTexture(groundGl.TEXTURE_2D, groundTexture);
groundGl.pixelStorei(groundGl.UNPACK_FLIP_Y_WEBGL, false); groundGl.pixelStorei(groundGl.UNPACK_FLIP_Y_WEBGL, true);
groundGl.texImage2D(groundGl.TEXTURE_2D, 0, groundGl.RGBA, groundGl.RGBA, groundGl.UNSIGNED_BYTE, groundCanvas); groundGl.texImage2D(groundGl.TEXTURE_2D, 0, groundGl.RGBA, groundGl.RGBA, groundGl.UNSIGNED_BYTE, groundCanvas);
groundGl.texParameteri(groundGl.TEXTURE_2D, groundGl.TEXTURE_WRAP_S, groundGl.CLAMP_TO_EDGE); groundGl.texParameteri(groundGl.TEXTURE_2D, groundGl.TEXTURE_WRAP_S, groundGl.CLAMP_TO_EDGE);
groundGl.texParameteri(groundGl.TEXTURE_2D, groundGl.TEXTURE_WRAP_T, groundGl.CLAMP_TO_EDGE); groundGl.texParameteri(groundGl.TEXTURE_2D, groundGl.TEXTURE_WRAP_T, groundGl.CLAMP_TO_EDGE);