/** * BoxShadow SDF 쉐이더 * Rectangle(0.0)과 Ellipse(1.0) 모두를 지원합니다. */ export declare const shadowVertex = "\n attribute vec2 position;\n attribute vec2 uv;\n uniform mat4 uModelMatrix;\n uniform mat4 uViewMatrix;\n uniform mat4 uProjectionMatrix;\n varying vec2 vUV;\n\n void main() {\n vUV = uv;\n gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * vec4(position, 0.0, 1.0);\n }\n"; export declare const shadowFragment = "\n precision highp float;\n uniform vec4 uColor;\n uniform float uOpacity;\n uniform vec2 uSize; // Quad size (includes blur padding)\n uniform vec2 uBoxSize; // Actual object size (w, h)\n uniform vec2 uOffset; // [offsetX, offsetY]\n uniform float uBlur;\n uniform float uSpread;\n uniform float uIsEllipse;\n uniform vec4 uBorderRadius; // [TR, BR, TL, BL]\n varying vec2 vUV;\n\n float sdRoundedBox(vec2 p, vec2 b, vec4 r) {\n r.xy = (p.x > 0.0) ? r.xy : r.zw;\n r.x = (p.y > 0.0) ? r.x : r.y;\n vec2 q = abs(p) - b + r.x;\n return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r.x;\n }\n\n void main() {\n // p is pixel mapped: center of the object is (0,0)\n vec2 p = (vUV - 0.5) * uSize;\n \n // Shadow center is offset from the object center\n // We negate uOffset.y because WebGL UV +y is typically UP, whereas CSS offset +y is DOWN.\n vec2 shadowP = p - vec2(uOffset.x, -uOffset.y);\n \n float d = 0.0;\n float innerMask = 0.0;\n vec2 radius = uBoxSize * 0.5;\n\n if (uIsEllipse > 0.5) {\n if (radius.x <= 0.0 || radius.y <= 0.0) {\n discard;\n }\n vec2 scaledShadowP = shadowP / radius;\n d = (length(scaledShadowP) - 1.0) * min(radius.x, radius.y);\n \n vec2 scaledInnerP = p / radius;\n innerMask = (length(scaledInnerP) - 1.0) * min(radius.x, radius.y);\n } else {\n d = sdRoundedBox(shadowP, radius, uBorderRadius);\n innerMask = sdRoundedBox(p, radius, uBorderRadius);\n }\n\n // Apply shadow spread\n d -= uSpread;\n\n float alpha = 1.0;\n if (uBlur > 0.0) {\n alpha = 1.0 - smoothstep(-uBlur, uBlur, d);\n } else {\n alpha = step(d, 0.0);\n }\n\n // Discard pixels that are INSIDE the actual box! (Hollow out the center)\n if (innerMask <= 0.0) discard;\n\n if (alpha <= 0.0) discard;\n\n float finalAlpha = uColor.a * uOpacity * alpha;\n gl_FragColor = vec4(uColor.rgb * finalAlpha, finalAlpha);\n }\n";