add iconGrowZoom for structures that scale with deep zoom

Previously structures capped at iconScale = 1.0 once zoomed past
iconScaleFactorZoomedOut, staying at a fixed pixel size no matter how
far you zoomed in. They felt overlaid on the map instead of part of it.

Add a third zoom band controlled by structure.iconGrowZoom. Past this
threshold iconScale = uZoom / iconGrowZoom — structures grow with the
canvas (world-anchored, fixed map-area coverage). Plumbed via the
uIconGrowZoom uniform on StructurePass.

Default 7 keeps normal play unchanged; only kicks in at deep zoom.
This commit is contained in:
evanpelle
2026-05-16 17:34:53 -07:00
parent bb619c2c44
commit e87e2cd58c
4 changed files with 19 additions and 2 deletions
@@ -76,6 +76,7 @@ export class StructurePass {
private uDotsThreshold: WebGLUniformLocation;
private uDotScale: WebGLUniformLocation;
private uScaleFactor: WebGLUniformLocation;
private uIconGrowZoom: WebGLUniformLocation;
private uShapeScales: WebGLUniformLocation;
private uIconFills: WebGLUniformLocation;
private uGhostAlpha: WebGLUniformLocation;
@@ -147,6 +148,7 @@ export class StructurePass {
"uDotsThreshold",
)!;
this.uScaleFactor = gl.getUniformLocation(this.program, "uScaleFactor")!;
this.uIconGrowZoom = gl.getUniformLocation(this.program, "uIconGrowZoom")!;
this.uShapeScales = gl.getUniformLocation(this.program, "uShapeScales")!;
this.uIconFills = gl.getUniformLocation(this.program, "uIconFills")!;
this.uGhostAlpha = gl.getUniformLocation(this.program, "uGhostAlpha")!;
@@ -334,6 +336,7 @@ export class StructurePass {
gl.uniform1f(this.uDotsThreshold, ss.dotsZoomThreshold);
gl.uniform1f(this.uDotScale, ss.dotScale);
gl.uniform1f(this.uScaleFactor, ss.iconScaleFactorZoomedOut);
gl.uniform1f(this.uIconGrowZoom, ss.iconGrowZoom);
// Build per-structure uniform arrays from settings, ordered by atlas column
const scales = new Float32Array(ATLAS_COLS);
+3 -2
View File
@@ -82,10 +82,11 @@
"railAlpha": 1
},
"structure": {
"iconSize": 65,
"iconSize": 50,
"dotsZoomThreshold": 1.2,
"dotScale": 0.3,
"iconScaleFactorZoomedOut": 3.5,
"iconScaleFactorZoomedOut": 3,
"iconGrowZoom": 7,
"shapes": {
"City": {
"scale": 1,
+7
View File
@@ -89,6 +89,13 @@ export interface RenderSettings {
/** Icon size multiplier when zoomed out past dotsZoomThreshold. */
dotScale: number;
iconScaleFactorZoomedOut: number;
/**
* Zoom level at which structures begin growing with the canvas.
* Below this zoom, structures stay at a fixed screen size (capped).
* Above this zoom, they grow proportionally to zoom — i.e. world-anchored,
* so they cover a fixed area of the map.
*/
iconGrowZoom: number;
shapes: Record<string, { scale: number; iconFill: number }>;
highlightOutlineWidth: number;
highlightDimAlpha: number;
@@ -14,6 +14,7 @@ uniform float uIconSize;
uniform float uDotsThreshold;
uniform float uDotScale;
uniform float uScaleFactor;
uniform float uIconGrowZoom;
uniform float uShapeScales[ATLAS_COLS];
uniform float uIconFills[ATLAS_COLS];
@@ -38,6 +39,11 @@ void main() {
float iconScale;
if (uZoom <= uDotsThreshold) {
iconScale = uDotScale;
} else if (uZoom >= uIconGrowZoom) {
// World-anchored: grow proportionally to zoom so the structure covers a
// fixed area of the map. Past this zoom, structures should feel like
// they're "on" the canvas rather than overlaid at constant pixel size.
iconScale = uZoom / uIconGrowZoom;
} else {
iconScale = min(1.0, uZoom / uScaleFactor);
}