// luma.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import type {ShaderPass} from '@luma.gl/shadertools'; import {random} from '@luma.gl/shadertools'; const source = /* wgsl */ `\ struct triangleBlurUniforms { radius: f32, delta: vec2f, }; @group(0) @binding(auto) var triangleBlur: triangleBlurUniforms; fn triangleBlur_sampleColor( sourceTexture: texture_2d, sourceTextureSampler: sampler, texSize: vec2f, texCoord: vec2f ) -> vec4f { let adjustedDelta = triangleBlur.delta * triangleBlur.radius / texSize; var color = vec4f(0.0); var total = 0.0; /* randomize the lookup values to hide the fixed number of samples */ let offset = random(vec3f(12.9898, 78.233, 151.7182), 0.0); for (var t = -30.0; t <= 30.0; t += 1.0) { let percent = (t + offset - 0.5) / 30.0; let weight = 1.0 - abs(percent); let offsetColor = textureSample( sourceTexture, sourceTextureSampler, texCoord + adjustedDelta * percent ); /* switch to pre-multiplied alpha to correctly blur transparent images */ let premultipliedOffsetColor = vec4f(offsetColor.rgb * vec3f(offsetColor.a), offsetColor.a); color += premultipliedOffsetColor * weight; total += weight; } color /= total; /* switch back from pre-multiplied alpha */ let unpremultipliedRgb = color.rgb / vec3f(color.a + 0.00001); return vec4f(unpremultipliedRgb, color.a); } `; const fs = /* glsl */ `\ layout(std140) uniform triangleBlurUniforms { float radius; vec2 delta; } triangleBlur; vec4 triangleBlur_sampleColor(sampler2D source, vec2 texSize, vec2 texCoord) { vec2 adjustedDelta = triangleBlur.delta * triangleBlur.radius / texSize; vec4 color = vec4(0.0); float total = 0.0; /* randomize the lookup values to hide the fixed number of samples */ float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0); for (float t = -30.0; t <= 30.0; t++) { float percent = (t + offset - 0.5) / 30.0; float weight = 1.0 - abs(percent); vec4 offsetColor = texture(source, texCoord + adjustedDelta * percent); /* switch to pre-multiplied alpha to correctly blur transparent images */ offsetColor.rgb *= offsetColor.a; color += offsetColor * weight; total += weight; } color = color / total; /* switch back from pre-multiplied alpha */ color.rgb /= color.a + 0.00001; return color; } `; /** * @filter Triangle Blur * @description This is the most basic blur filter, which convolves the image with a * pyramid filter. The pyramid filter is separable and is applied as two * perpendicular triangle filters. */ export type TriangleBlurProps = { /** The radius of the pyramid convolved with the image. */ radius?: number; /** @deprecated internal property */ delta?: [number, number]; }; export type TriangleBlurUniforms = TriangleBlurProps; /** * @filter Triangle Blur * @description This is the most basic blur filter, which convolves the image with a * pyramid filter. The pyramid filter is separable and is applied as two * perpendicular triangle filters. */ export const triangleBlur = { name: 'triangleBlur', dependencies: [random], source, fs, props: {} as TriangleBlurProps, uniforms: {} as TriangleBlurUniforms, uniformTypes: { radius: 'f32', delta: 'vec2' }, propTypes: { radius: {value: 20, min: 0, softMax: 100}, delta: {value: [1, 0], private: true} }, passes: [ {sampler: true, uniforms: {delta: [1, 0]}}, {sampler: true, uniforms: {delta: [0, 1]}} ] } as const satisfies ShaderPass;