如何让feTurbulence与feDisplacementMap滤镜缩放后渲染一致?
解决SVG滤镜缩放后渲染不一致的问题
核心原因
你当前使用filterUnits="userSpaceOnUse",这个单位基于SVG的用户坐标空间(即SVG的宽高数值)计算滤镜效果:
feTurbulence的baseFrequency是「每单位用户空间的噪声周期数」,SVG放大N倍后,相同数值会让噪声密度变为原来的N倍;feDisplacementMap的scale是「用户空间单位的偏移量」,SVG放大N倍后,相同数值会让偏移的相对比例变为原来的1/N。
直接按比例调整参数无效,是因为两个参数的缩放逻辑完全相反,需要分别计算。
解决方案
方法1:保持userSpaceOnUse,按缩放比例反向调整参数
假设原始SVG尺寸为W×H,缩放后尺寸为W'×H',等比缩放比例k = W'/W = H'/H:
- 新的
baseFrequency = 原始baseFrequency / k(降低噪声密度,匹配缩放后的空间) - 新的
scale = 原始scale × k(增大偏移量,保持相对比例一致)
示例验证(放大2倍)
原始参数:baseFrequency="0.05",scale="10"
缩放后参数:baseFrequency="0.025",scale="20"
修改后的放大版SVG代码:
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="264"> <defs> <filter id="filter2" x="0%" y="0%" width="100%" height="100%" filterUnits="userSpaceOnUse"> <feTurbulence baseFrequency="0.025" result="NOISE" type="turbulence" /> <feDisplacementMap in="SourceGraphic" in2="NOISE" result="RESULT" scale="20" xChannelSelector="R" yChannelSelector="R"></feDisplacementMap> </filter> </defs> <image x="0" y="0" width="600" height="264" href="https://i.sstatic.net/SS7N6.png" filter="url(#filter2)"></image> </svg>
方法2:改用filterUnits="objectBoundingBox",自动适配缩放
将滤镜单位改为objectBoundingBox,此时所有滤镜参数基于元素的边界框比例计算,无需手动调整参数,SVG缩放时效果会自动保持一致。
修改后的通用SVG代码
原始尺寸和放大尺寸的SVG仅需修改宽高,滤镜参数完全一致:
<!-- 300x132 版本 --> <svg xmlns="http://www.w3.org/2000/svg" width="300" height="132"> <defs> <filter id="filter1" x="0%" y="0%" width="100%" height="100%" filterUnits="objectBoundingBox"> <feTurbulence baseFrequency="0.05" result="NOISE" type="turbulence" /> <feDisplacementMap in="SourceGraphic" in2="NOISE" result="RESULT" scale="10" xChannelSelector="R" yChannelSelector="R"></feDisplacementMap> </filter> </defs> <image x="0" y="0" width="300" height="132" href="https://i.sstatic.net/osUI3.png" filter="url(#filter1)"></image> </svg>
<!-- 600x264 放大版本 --> <svg xmlns="http://www.w3.org/2000/svg" width="600" height="264"> <defs> <filter id="filter2" x="0%" y="0%" width="100%" height="100%" filterUnits="objectBoundingBox"> <feTurbulence baseFrequency="0.05" result="NOISE" type="turbulence" /> <feDisplacementMap in="SourceGraphic" in2="NOISE" result="RESULT" scale="10" xChannelSelector="R" yChannelSelector="R"></feDisplacementMap> </filter> </defs> <image x="0" y="0" width="600" height="264" href="https://i.sstatic.net/SS7N6.png" filter="url(#filter2)"></image> </svg>
内容的提问来源于stack exchange,提问作者Dady
相关产品推荐
相关产品推荐

