diff --git a/src/client/render/gl/RenderSettings.ts b/src/client/render/gl/RenderSettings.ts index 180317948..cca1cd316 100644 --- a/src/client/render/gl/RenderSettings.ts +++ b/src/client/render/gl/RenderSettings.ts @@ -257,6 +257,7 @@ export interface RenderSettings { }; fx: { shockwaveRingWidth: number; + attackRingScreenPx: number; // screen px — attack ring quad half-size (visible outer ring = 0.8×) nukeShockwaveDurationMs: number; nukeShockwaveRadiusFactor: number; samShockwaveDurationMs: number; diff --git a/src/client/render/gl/debug/Layout.ts b/src/client/render/gl/debug/Layout.ts index e885f11fa..242b935f9 100644 --- a/src/client/render/gl/debug/Layout.ts +++ b/src/client/render/gl/debug/Layout.ts @@ -332,6 +332,15 @@ export function buildTree(s: RenderSettings, d: RenderSettings): DebugNode[] { folder("FX", [ slider(s.fx, "shockwaveRingWidth", d.fx, 0.01, 0.2, 0.005), + slider( + s.fx, + "attackRingScreenPx", + d.fx, + 5, + 60, + 1, + "Attack Ring Size (px)", + ), slider( s.fx, "nukeShockwaveDurationMs", diff --git a/src/client/render/gl/passes/fx-pass/FxAttackRingPass.ts b/src/client/render/gl/passes/fx-pass/FxAttackRingPass.ts index c522e2880..4c0932bd7 100644 --- a/src/client/render/gl/passes/fx-pass/FxAttackRingPass.ts +++ b/src/client/render/gl/passes/fx-pass/FxAttackRingPass.ts @@ -50,6 +50,7 @@ export class FxAttackRingPass { private uTilesPerPx: WebGLUniformLocation; private uTime: WebGLUniformLocation; private uRingWidth: WebGLUniformLocation; + private uRingScreenPx: WebGLUniformLocation; private vao: WebGLVertexArrayObject; private instanceBuf: DynamicInstanceBuffer; private ringCount = 0; @@ -65,6 +66,7 @@ export class FxAttackRingPass { this.uTilesPerPx = gl.getUniformLocation(this.program, "uTilesPerPx")!; this.uTime = gl.getUniformLocation(this.program, "uTime")!; this.uRingWidth = gl.getUniformLocation(this.program, "uRingWidth")!; + this.uRingScreenPx = gl.getUniformLocation(this.program, "uRingScreenPx")!; const glBuf = gl.createBuffer()!; this.instanceBuf = new DynamicInstanceBuffer( @@ -182,6 +184,7 @@ export class FxAttackRingPass { gl.uniform1f(this.uTilesPerPx, 1 / zoom); gl.uniform1f(this.uTime, performance.now() / 1000); gl.uniform1f(this.uRingWidth, this.settings.fx.shockwaveRingWidth); + gl.uniform1f(this.uRingScreenPx, this.settings.fx.attackRingScreenPx); gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceBuf.buffer); gl.bufferSubData( gl.ARRAY_BUFFER, diff --git a/src/client/render/gl/render-settings.json b/src/client/render/gl/render-settings.json index a9f5ccc87..21a6c90be 100644 --- a/src/client/render/gl/render-settings.json +++ b/src/client/render/gl/render-settings.json @@ -216,6 +216,7 @@ }, "fx": { "shockwaveRingWidth": 0.04, + "attackRingScreenPx": 30, "nukeShockwaveDurationMs": 1500, "nukeShockwaveRadiusFactor": 1.5, "samShockwaveDurationMs": 800, diff --git a/src/client/render/gl/shaders/fx/attack-ring.vert.glsl b/src/client/render/gl/shaders/fx/attack-ring.vert.glsl index 3c66df397..139b097a2 100644 --- a/src/client/render/gl/shaders/fx/attack-ring.vert.glsl +++ b/src/client/render/gl/shaders/fx/attack-ring.vert.glsl @@ -6,18 +6,18 @@ layout(location = 1) in vec3 aInstData; // x, y, alpha uniform mat3 uCamera; uniform float uTilesPerPx; +// Quad half-size in screen px; visible outer ring = 0.8× (frag OUTER_R), +// the rest is headroom for SDF AA. +uniform float uRingScreenPx; out vec2 vLocalPos; flat out float vAlpha; -// Upstream outer ring = 16 screen-px; quad needs headroom for SDF AA. -const float RING_SCREEN_PX = 20.0; - void main() { vec2 center = vec2(aInstData.x + 0.5, aInstData.y + 0.5); vAlpha = aInstData.z; - float worldRadius = RING_SCREEN_PX * uTilesPerPx; + float worldRadius = uRingScreenPx * uTilesPerPx; vec2 worldPos = center + (aPos - 0.5) * worldRadius * 2.0; vec3 clip = uCamera * vec3(worldPos, 1.0);