Как смягчить действие фильтра SVG? Получить более сглаженные границы?

Есть работа фильтров SVG и последующая анимация через JS. Настраиваю feTurbulence, передаю на вход feDisplacementMap, но получаю довольно "жесткий" результат - границы эффекта угловатые, не сглаженные.

const SCALE_MAX = 1;
const SCALE_MIN = 0.2;
const SCALE_STEP = 0.004;

let disp_map = document.querySelector('feDisplacementMap');
let turbulence = document.querySelector('feTurbulence');

let scale = SCALE_MIN + SCALE_STEP;
let dir = 1;

draw();

function draw(){
    disp_map.setAttribute('scale', scale*10);
    turbulence.setAttribute('baseFrequency', scale/10);
    
    requestAnimationFrame(draw);
    
    if(scale >= SCALE_MAX || scale <= SCALE_MIN) dir = -dir;
        
    scale += SCALE_STEP * dir;       
}
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
    <filter id="disp-filter">
        <feTurbulence baseFrequency="0.3" type="turbulence" numOctaves="2" result="turbulence"/>
        <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="0.5"/>
    </filter>   
    <text font-size="40px" textLength="80%" y="40" x ="100" fill="blue" text-anchor="middle"
            style="filter: url(#disp-filter); font-family: sans-serif; font-weight: bold">ВОДА</text>
</svg>

Для сглаживания пробую добавить feGaussianBlur после feTurbulence и получаю совершенно неожиданный результат:

const SCALE_MAX = 1;
const SCALE_MIN = 0.2;
const SCALE_STEP = 0.004;

let disp_map = document.querySelector('feDisplacementMap');
let turbulence = document.querySelector('feTurbulence');

let scale = SCALE_MIN + SCALE_STEP;
let dir = 1;

draw();

function draw(){
    disp_map.setAttribute('scale', scale*10);
    turbulence.setAttribute('baseFrequency', scale/10);
    
    requestAnimationFrame(draw);
    
    if(scale >= SCALE_MAX || scale <= SCALE_MIN) dir = -dir;
        
    scale += SCALE_STEP * dir;       
}
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
  <filter id="disp-filter">
      <feTurbulence baseFrequency="0.3" type="turbulence" numOctaves="2" result="turbulence"/>
      <feGaussianBlur in2="turbulence" in="SourceGraphic" stdDeviation="1" result="blur" />
      <feDisplacementMap in2="blur" in="SourceGraphic" scale="0.5"/>
  </filter>   
  <text font-size="40px" textLength="80%" y="40" x ="100" fill="blue" text-anchor="middle"
         style="filter: url(#disp-filter); font-family: sans-serif; font-weight: bold">ВОДА</text>
</svg>

Если выставляю blur дополнительным фильтром в style элемента text, или пробую размытие feDisplacementMap, то любой эффект кроме blur пропадает.

Как можно доработать фильтр (<filter id="disp-filter">), чтобы получить более сглаженные границы?


Ответы (2 шт):

Автор решения: UModeL

Почему бы не использовать комбинацию из CSS и SVG фильтров? Свойство filter допускает цепочки. Кстати, если размытие в 1px слишком велико, то в фильтре blur() возможно указывать дробное значение пикселей.

const SCALE_MAX = 1;
const SCALE_MIN = 0.2;
const SCALE_STEP = 0.004;

let disp_map = document.querySelector('feDisplacementMap');
let turbulence = document.querySelector('feTurbulence');

let scale = SCALE_MIN + SCALE_STEP;
let dir = 1;

draw();

function draw(){
    disp_map.setAttribute('scale', scale*10);
    turbulence.setAttribute('baseFrequency', scale/10);
    
    requestAnimationFrame(draw);
    
    if(scale >= SCALE_MAX || scale <= SCALE_MIN) dir = -dir;
        
    scale += SCALE_STEP * dir;       
}
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
    <filter id="disp-filter">
        <feTurbulence baseFrequency="0.3" type="turbulence" numOctaves="2" result="turbulence"/>
        <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="0.5"/>
    </filter>   
    <text font-size="40px" textLength="80%" y="40" x ="100" fill="blue" text-anchor="middle"
            style="filter: url(#disp-filter) blur(.6px); font-family: sans-serif; font-weight: bold">ВОДА</text>
</svg>

→ Ссылка
Автор решения: Leonid

Согласно ответу UModel создал отдельно фильтр feGaussianBlur и добавил в стили цепочкой. Добавляю этот вариант потому, что он позволяет величину размытия указать в относительных единицах, а не привязываться к пикселям:

const SCALE_MAX = 1;
const SCALE_MIN = 0.2;
const SCALE_STEP = 0.004;

let disp_map = document.querySelector('feDisplacementMap');
let turbulence = document.querySelector('feTurbulence');

let scale = SCALE_MIN + SCALE_STEP;
let dir = 1;

draw();

function draw(){
    disp_map.setAttribute('scale', scale*10);
    turbulence.setAttribute('baseFrequency', scale/10);
    
    requestAnimationFrame(draw);
    
    if(scale >= SCALE_MAX || scale <= SCALE_MIN) dir = -dir;
        
    scale += SCALE_STEP * dir;       
}
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<filter id="disp-filter">
    <feTurbulence baseFrequency="0.3" type="turbulence" numOctaves="2" result="turbulence"/>
    <feDisplacementMap in2="turbulence" in="SourceGraphic" scale="0.5"/>
</filter>
<filter id='blur-filter'>
    <feGaussianBlur stdDeviation="0.4"/>
</filter>
<text font-size="40px" textLength="80%" y="40" x ="100" fill="blue" text-anchor="middle"
        style="filter: url(#disp-filter) url(#blur-filter); font-family: sans-serif; font-weight: bold">ВОДА</text>
</svg>

→ Ссылка