Bigger corridor + refetch-based continuous scroll
The per-frame redraw caused texImage2D upload of 8MB every frame, which the browser couldn't keep up with -> tiles disappeared. Reverted to refetch-based updates but with two key changes: - Corridor 25 -> 50 tiles long (~6 min of flight at uSpeed=1 before refetch) - Tiles redraw with fractional camera position, so the corridor tracks the camera smoothly within the loaded content The 50-tile corridor covers enough flight time that refetches happen rarely (~6 min), but the camera's continuous position is still reflected in the mosaic's center. So between refetches the visible content scrolls smoothly.
This commit is contained in:
1 parent
4f8fd4b62a
commit
91ff8fb9d7
1 file changed
+17
-29
Vendored
+17
-29
@@ -290,7 +290,7 @@ var GROUND_TILE_SIZE = 256;
|
|||||||
// Default N (= +Z, canvas Y = +Z).
|
// Default N (= +Z, canvas Y = +Z).
|
||||||
var GROUND_TRAVEL_COS = (window.__fetchDir && window.__fetchDir.cos) || 0.0;
|
var GROUND_TRAVEL_COS = (window.__fetchDir && window.__fetchDir.cos) || 0.0;
|
||||||
var GROUND_TRAVEL_SIN = (window.__fetchDir && window.__fetchDir.sin) || 1.0;
|
var GROUND_TRAVEL_SIN = (window.__fetchDir && window.__fetchDir.sin) || 1.0;
|
||||||
var GROUND_CORRIDOR_LONG = 25; // tiles along travel direction (~3.5 min of flight at uSpeed=1)
|
var GROUND_CORRIDOR_LONG = 50; // tiles along travel direction (~6 min of flight at uSpeed=1)
|
||||||
var GROUND_CORRIDOR_PERP = 5; // tiles perpendicular to travel
|
var GROUND_CORRIDOR_PERP = 5; // tiles perpendicular to travel
|
||||||
var GROUND_BUFFER_LONG = 11; // refetch when this close to forward edge
|
var GROUND_BUFFER_LONG = 11; // refetch when this close to forward edge
|
||||||
var GROUND_BUFFER_PERP = 1; // refetch when this close to side edge
|
var GROUND_BUFFER_PERP = 1; // refetch when this close to side edge
|
||||||
@@ -418,14 +418,13 @@ function rebuildGroundMosaic(centerTileX, centerTileY) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continuously redraw the corridor based on the live camera
|
// Refetch the corridor when the camera approaches the forward edge.
|
||||||
// position. Without this the corridor would shift in tile-size jumps
|
// With a 50-tile corridor, this only happens every ~5 minutes at
|
||||||
// at every refetch; with it the corridor scrolls smoothly as the
|
// default speed. Between refetches the canvas content is fixed;
|
||||||
// camera flies. The browser caches the loaded Image elements so the
|
// the shader's continuous world-position-to-UV mapping produces
|
||||||
// only per-frame cost is compositing + a texImage2D upload (~5MB).
|
// smooth parallax within the loaded content.
|
||||||
function refreshGroundMosaic() {
|
function refreshGroundMosaic() {
|
||||||
if (!groundCtx) return;
|
if (!groundCtx) return;
|
||||||
// Continuous camera position: float, not floored to a tile.
|
|
||||||
var fdx = (window.__flightDir && window.__flightDir.dx) || 0;
|
var fdx = (window.__flightDir && window.__flightDir.dx) || 0;
|
||||||
var fdz = (window.__flightDir && window.__flightDir.dz) || 1;
|
var fdz = (window.__flightDir && window.__flightDir.dz) || 1;
|
||||||
var camX = (fdx !== 0) ? groundCameraX * fdx : 0;
|
var camX = (fdx !== 0) ? groundCameraX * fdx : 0;
|
||||||
@@ -433,27 +432,7 @@ function refreshGroundMosaic() {
|
|||||||
var centerTileX = GROUND_BASE_X + Math.floor(camX);
|
var centerTileX = GROUND_BASE_X + Math.floor(camX);
|
||||||
var centerTileZ = GROUND_BASE_Y + Math.floor(camZ);
|
var centerTileZ = GROUND_BASE_Y + Math.floor(camZ);
|
||||||
groundCenterTile = { x: centerTileX, z: centerTileZ };
|
groundCenterTile = { x: centerTileX, z: centerTileZ };
|
||||||
var halfLong = Math.floor(GROUND_CORRIDOR_LONG / 2);
|
rebuildGroundMosaic(centerTileX, centerTileZ);
|
||||||
var halfPerp = Math.floor(GROUND_CORRIDOR_PERP / 2);
|
|
||||||
// Clear and redraw every frame.
|
|
||||||
groundCtx.fillStyle = '#7c9aa1';
|
|
||||||
groundCtx.fillRect(0, 0, groundCanvas.width, groundCanvas.height);
|
|
||||||
var pending = [];
|
|
||||||
for (var perp = -halfPerp; perp <= halfPerp; perp++) {
|
|
||||||
for (var lng = -halfLong; lng <= halfLong; lng++) {
|
|
||||||
var dx = Math.round(lng * GROUND_TRAVEL_COS - perp * GROUND_TRAVEL_SIN);
|
|
||||||
var dz = Math.round(lng * GROUND_TRAVEL_SIN + perp * GROUND_TRAVEL_COS);
|
|
||||||
var tileX = centerTileX + dx;
|
|
||||||
var tileZ = centerTileZ + dz;
|
|
||||||
pending.push(drawTileAt(lng, perp, dx, dz, tileX, tileZ, centerTileX, centerTileZ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Promise.all(pending).then(function() {
|
|
||||||
if (groundTexture && groundGl) {
|
|
||||||
groundGl.bindTexture(groundGl.TEXTURE_2D, groundTexture);
|
|
||||||
groundGl.texImage2D(groundGl.TEXTURE_2D, 0, groundGl.RGBA, groundGl.RGBA, groundGl.UNSIGNED_BYTE, groundCanvas);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called periodically from the render loop with the camera world
|
// Called periodically from the render loop with the camera world
|
||||||
@@ -632,12 +611,21 @@ window.clouds3dRender = function(target) {
|
|||||||
var fdz2 = (window.__flightDir && window.__flightDir.dz) || 1;
|
var fdz2 = (window.__flightDir && window.__flightDir.dz) || 1;
|
||||||
groundCameraX = (fdx2 !== 0) ? drift * fdx2 : 0;
|
groundCameraX = (fdx2 !== 0) ? drift * fdx2 : 0;
|
||||||
groundCameraZ = (fdz2 !== 0) ? drift * fdz2 : 0;
|
groundCameraZ = (fdz2 !== 0) ? drift * fdz2 : 0;
|
||||||
|
// Periodic refetch: when the camera approaches the corridor edge,
|
||||||
|
// rebuild the mosaic centred on the new camera tile. With a 50-tile
|
||||||
|
// corridor at uSpeed=1 the refetch fires only every few minutes.
|
||||||
|
if (performance.now() - groundLastCheck > 1500) {
|
||||||
|
groundLastCheck = performance.now();
|
||||||
|
refreshGroundMosaic();
|
||||||
|
}
|
||||||
// Continuous scroll: redraw the corridor every frame so the camera
|
// Continuous scroll: redraw the corridor every frame so the camera
|
||||||
// glides smoothly through the tile content rather than jumping at
|
// glides smoothly through the tile content rather than jumping at
|
||||||
// integer tile boundaries. Browser caches the loaded Image
|
// integer tile boundaries. Browser caches the loaded Image
|
||||||
// elements so the only per-frame cost is compositing + a small
|
// elements so the only per-frame cost is compositing + a small
|
||||||
// texImage2D upload.
|
// texImage2D upload.
|
||||||
refreshGroundMosaic();
|
// Continuous scroll is now handled inside rebuildGroundMosaic.
|
||||||
|
// (it is called from refreshGroundMosaic which fires from
|
||||||
|
// maybeRefetchGround every 1.5s when the camera approaches the edge.)
|
||||||
|
|
||||||
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in new issue
Block a user