Как смягчить действие фильтра 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 шт):
Почему бы не использовать комбинацию из 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>
Согласно ответу 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>