diff --git a/src/frontend/src/features/rooms/livekit/components/blur/wip2.ts b/src/frontend/src/features/rooms/livekit/components/blur/wip2.ts index b3d0617f..e3197810 100644 --- a/src/frontend/src/features/rooms/livekit/components/blur/wip2.ts +++ b/src/frontend/src/features/rooms/livekit/components/blur/wip2.ts @@ -26,63 +26,60 @@ const FRAGMENT_SHADER = `#version 300 es uniform vec2 texelSize; uniform float blurAmount; - const float sigma_s = 2.0; // Spatial sigma (distance-based) - const int KERNEL_RADIUS = 2; // Kernel size is (2 * KERNEL_RADIUS + 1) x (2 * KERNEL_RADIUS + 1) - in vec2 vTex; out vec4 fragColor; + // Smoothing function for mask transitions vec4 maskSmoothing() { - vec4 centerColor = texture(maskTexture, vTex); - float sumWeight = 0.0; - vec4 sumColor = vec4(0.0); - - for (int i = -KERNEL_RADIUS; i <= KERNEL_RADIUS; i++) { - for (int j = -KERNEL_RADIUS; j <= KERNEL_RADIUS; j++) { - vec2 offset = vec2(float(i), float(j)) * texelSize; - vec4 neighborColor = texture(maskTexture, vTex + offset); - - // Spatial weight (Gaussian distance) - float spatialDist = length(vec2(i, j)); - float spatialWeight = exp(-(spatialDist * spatialDist) / (2.0 * sigma_s * sigma_s)); - - // Accumulate weighted color - sumColor += neighborColor * spatialWeight; - sumWeight += spatialWeight; - } - } - - // Normalize the result to avoid darkening - return sumColor / sumWeight; + // Sample the mask at the current texel + float maskValue = texture(maskTexture, vTex).r; + + // Apply smoothing to reduce aliasing at mask edges + float smoothedMask = smoothstep(0.2, 0.8, maskValue); + + return vec4(smoothedMask); + } + + // Compute Gaussian weight based on distance and blur amount + float gaussianWeight(float x, float y, float sigma) { + float sigmaSq = sigma * sigma; + float distanceSq = x * x + y * y; + + // Gaussian function: (1/(2πσ²)) * e^(-((x²+y²)/(2σ²))) + return exp(-distanceSq / (2.0 * sigmaSq)); } - - // Gaussian blur weights and offsets - const float offset[5] = float[](0.0, 1.0, 2.0, 3.0, 4.0); - const float weight[5] = float[](0.2270270270, 0.1945945946, 0.1216216216, - 0.0540540541, 0.0162162162); - - const float radius = 0.01; void main() { vec4 centerColor = texture(backgroundTexture, vTex); - + // Apply bilateral filtering on the mask before using it vec4 personMask = maskSmoothing(); - - vec4 frameColor = centerColor * weight[0]; - - for (int i = 1; i < 5; i++) { - vec2 offsetVec = vec2(offset[i]) * texelSize * radius; - - vec2 texCoord = vTex + offsetVec; - frameColor += texture(backgroundTexture, texCoord) * weight[i] * personMask.r; - - texCoord = vTex - offsetVec; - frameColor += texture(backgroundTexture, texCoord) * weight[i] * personMask.r; + + // Dynamic 5x5 Gaussian blur + vec4 blurredColor = vec4(0.0); + float totalWeight = 0.0; + + // Compute effective sigma from blur amount (adjust as needed) + float sigma = max(0.1, blurAmount) + 50.0; + + // Apply 5x5 kernel with dynamic weights + for (int y = -10; y <= 10; y++) { + for (int x = -10; x <= 10; x++) { + // Calculate Gaussian weight for this offset + float weight = gaussianWeight(float(x), float(y), sigma); + totalWeight += weight; + + vec2 offset = vec2(float(x), float(y)) * texelSize; + vec2 sampleCoord = vTex + offset; + blurredColor += texture(backgroundTexture, sampleCoord) * weight; + } } - - // Blend original color with blurred background - fragColor = mix(centerColor, frameColor, personMask.r); + + // Normalize by total weight + blurredColor /= totalWeight; + + // Blend original color with blurred background based on mask + fragColor = mix(centerColor, blurredColor, personMask.r); } `; @@ -120,17 +117,33 @@ export class BackgroundBlurShaderContext extends MPImageShaderContext { ) // Set texel size (for proper blur scaling) - const width = - background instanceof ImageData ? background.width : background.width || 1 - const height = - background instanceof ImageData - ? background.height - : background.height || 1 + let width = 1; + let height = 1; + + if (background instanceof ImageData) { + width = background.width; + height = background.height; + } else if (background instanceof HTMLCanvasElement) { + width = background.width; + height = background.height; + } else if (background instanceof HTMLImageElement) { + width = background.naturalWidth; + height = background.naturalHeight; + } else if (background instanceof HTMLVideoElement) { + width = background.videoWidth; + height = background.videoHeight; + } + + // Ensure we have valid dimensions to prevent division by zero + width = Math.max(width, 1); + height = Math.max(height, 1); gl.uniform2f(this.texelSizeUniform!, 1.0 / width, 1.0 / height) // Set blur amount - gl.uniform1f(this.blurAmountUniform!, blurAmount) + if (this.blurAmountUniform) { + gl.uniform1f(this.blurAmountUniform, blurAmount) + } } unbindTextures() { @@ -167,10 +180,10 @@ export class BackgroundBlurShaderContext extends MPImageShaderContext { gl.getUniformLocation(this.program!, 'texelSize'), 'Uniform location' ) - // this.blurAmountUniform = assertExists( - // gl.getUniformLocation(this.program!, 'blurAmount'), - // 'Uniform location' - // ) + this.blurAmountUniform = assertExists( + gl.getUniformLocation(this.program!, 'blurAmount'), + 'Uniform location' + ) } protected override configureUniforms(): void {