From 385b4dd686a3bb71282294180998158baf5e96e2 Mon Sep 17 00:00:00 2001 From: evanpelle Date: Fri, 5 Jun 2026 19:47:07 -0700 Subject: [PATCH] Add steady glow effect beneath hydrogen bomb Render a soft radial glow underneath the hydrogen bomb sprite in UnitPass. H-bomb instances draw an enlarged quad (hBombGlowScale) so there's room for the halo; a cell-space UV remap keeps the sprite at its normal size while the margin becomes glow area. The glow is a steady (non-pulsing) radial falloff in a warm amber, alpha-blended underneath the sprite and suppressed in alt/affiliation view. Detection uses a HYDROGEN_BOMB_COL shader define derived from UNIT_ORDER, so it tracks the atlas layout rather than hard-coding the column. All other units are unaffected (scale 1, same fillrate); this stays a single program / two instanced draw calls. Glow color, scale, strength, and falloff are exposed in render-settings.json for live tuning via the debug GUI. --- resources/atlases/unit-atlas.png | Bin 553 -> 578 bytes src/client/render/gl/RenderSettings.ts | 7 ++++ src/client/render/gl/passes/UnitPass.ts | 36 +++++++++++++++++- src/client/render/gl/render-settings.json | 8 +++- .../render/gl/shaders/unit/unit.frag.glsl | 34 ++++++++++++++--- .../render/gl/shaders/unit/unit.vert.glsl | 24 ++++++++---- 6 files changed, 94 insertions(+), 15 deletions(-) diff --git a/resources/atlases/unit-atlas.png b/resources/atlases/unit-atlas.png index 295bc00862f9bdb8dc7d0e746c021297915db905..77d9489cbe9b48bd7e743e52e442090f8f42cb02 100644 GIT binary patch delta 451 zcmV;!0X+Vx1i}Q6iGKzL04y#v$6i?g00EduL_t(o!|j<%ZUZ3aVb`%zrxo0M&bM zt^nEnem9ED1%U&AM^IBrTL|GXwl{ndKrL`)GMYknG2l3CsDBmcVvKbr@GIF0=YD*B zH`n`oe^cn5)U7q(oU6~kG!lhPdLKbF%0_(LTC4ThS%GuT)eyoGbO2CON>k9aGTR8c z7-O~8ZurbXgRpVvdYKHf8U1|3MWYfOY4evP0ss}Cy=-nR*bs&pClNM;ruAiX9)*oV zC)u|GISMd`On-t-S_6+(>4@$5va%6gDU9PPbh9VVtj#ara?XarlXD){E8crU;c3-i zbRKn#Lnzs|>ZVaWRZ8i;OKWh*_g(YR~6W$oP?}mxco_4Xd!Nwlw%Im^|G{80=Bd`FIbu-i>snep8*W tEh4o>v=67iy%awEr$MFKv{!e8egH2kK|;~~=iLAR002ovPDHLkV1mdv)#CsF delta 426 zcmV;b0agCO1gQj&iGKwh5ik!!g>X{<00DnVL_t(o!|jeD>MF)q^j|nv_O~Yh0L6Q6 zuK?LR&sLGSAaDS%IyI$aLI`WyDEMNGWe*rmL{sQ423!prN`C?!2Oep(!oDA$U)}dT zA9scBpl-be=Uh1g)1D}7t@}NQG{5>sz&Yni2tfoL0F;yx3%Xup+k-B~Sf*(*cyXbl zHXJ=4_cfZ)-y;qhg=nPBD?tPR3SMW~+SQXyw%?7 zi(6}Ji`^PivVRcXDfFWhI_}QHwfO;D&e>9Ua?ZQ?iuc}9czQV)?MEk8L)fzK= 0.0 && vCellUV.x <= 1.0 && + vCellUV.y >= 0.0 && vCellUV.y <= 1.0; + if (inSprite) { + vec2 atlasUV = vec2((vAtlasCol + vCellUV.x) / float(ATLAS_COLS), vCellUV.y); + texel = texture(uAtlas, atlasUV); + } - // Discard fully transparent pixels - if (texel.a < 0.01) discard; + // Outside the sprite: render the steady soft glow under the hydrogen bomb, + // otherwise discard. Glow is suppressed in alt (affiliation) view. + if (texel.a < 0.01) { + if (vGlow > 0.5 && uAltView == 0) { + float d = length(vQuadPos - 0.5) * 2.0; // 0 at center → ~1 at quad edge + float g = (1.0 - smoothstep(uHBombGlowInner, 1.0, d)) * uHBombGlowStrength; + if (g > 0.001) { + fragColor = vec4(uHBombGlowColor, g); + return; + } + } + discard; + } float gray = texel.r; diff --git a/src/client/render/gl/shaders/unit/unit.vert.glsl b/src/client/render/gl/shaders/unit/unit.vert.glsl index 640734d98..7bd39eb95 100644 --- a/src/client/render/gl/shaders/unit/unit.vert.glsl +++ b/src/client/render/gl/shaders/unit/unit.vert.glsl @@ -10,12 +10,15 @@ layout(location = 2) in vec2 aInstFlags; // atlasIdx (uint8→float), flags (uin uniform mat3 uCamera; uniform float uUnitSize; +uniform float uHBombGlowScale; // quad enlargement for the hydrogen bomb glow halo -out vec2 vLocalPos; -out vec2 vAtlasUV; +out vec2 vQuadPos; // quad coords [0,1] — drives the radial glow falloff +out vec2 vCellUV; // sprite cell coords; the central 1/scale region is the sprite +flat out float vAtlasCol; flat out float vOwnerID; flat out float vFlags; // 0.0 = normal, 1.0 = flicker, 2.0 = angry flat out float vHash; // per-instance hash for flicker phase offset +flat out float vGlow; // 1.0 if this instance is a hydrogen bomb (draw glow), else 0.0 void main() { float worldX = aInstPos.x; @@ -24,13 +27,20 @@ void main() { float atlasCol = aInstFlags.x; vFlags = aInstFlags.y; + vAtlasCol = atlasCol; // Position-based hash so each unit flickers independently vHash = fract(worldX * 0.1731 + worldY * 0.3179); + // Hydrogen bombs render an enlarged quad so there's room for a glow halo + // around the sprite. All other units keep scale 1 (no behavior change). + float isHBomb = step(abs(atlasCol - float(HYDROGEN_BOMB_COL)), 0.5); + vGlow = isHBomb; + float scale = mix(1.0, uHBombGlowScale, isHBomb); + // UNIT_SIZE is in world-space tiles — no zoom division needed. // Units scale with the map like territory tiles do. - float halfSize = uUnitSize * 0.5; + float halfSize = uUnitSize * 0.5 * scale; vec2 center = vec2(worldX + 0.5, worldY + 0.5); vec2 worldPos = center + (aPos - 0.5) * halfSize * 2.0; @@ -38,9 +48,9 @@ void main() { vec3 clip = uCamera * vec3(worldPos, 1.0); gl_Position = vec4(clip.xy, 0.0, 1.0); - vLocalPos = aPos; + vQuadPos = aPos; - // Atlas UV: map quad [0,1] to the correct column - float colU = (atlasCol + aPos.x) / float(ATLAS_COLS); - vAtlasUV = vec2(colU, aPos.y); + // Map the enlarged quad back to sprite cell space: the central 1/scale + // portion is the sprite, anything outside [0,1] is glow-only margin. + vCellUV = (aPos - 0.5) * scale + 0.5; }