我正在尝试编写一个 SVG 过滤器来在给定的形状上呈现波浪照明。所以在那个形状里面我想要波浪应用,但我不希望在那个形状之外没有可见的效果。据我所知,我不能将相同的图像源用于波浪的高度图和atop组合的目标域。所以我认为一个<feImage>元素可能用于从单独的渐变填充对象获取高度图。但到目前为止,我还没有成功地使该对象在滤镜效果区域内可见。
我到目前为止的代码:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1" width="512" height="512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<rect id="waveImg" x="-210" y="-105" width="420" height="210"
stroke="none" fill="url(#waveFill)"/>
<filter id="waveFilter">
<feImage xlink:href="#waveImg" result="waves"/>
<!-- feSpecularLighting and so on will be added later on -->
<feComposite operator="atop" in="waves" in2="SourceImage"/>
</filter>
</defs>
<g transform="translate(256 256)">
<!-- use xlink:href="#waveImg"/ works -->
<ellipse rx="200" ry="100" fill="#0000ff" stroke="none"
style="filter:url(#waveFilter)"/>
</g>
</svg>
Run Code Online (Sandbox Code Playgroud)
<feImage>状态的文档:
如果'xlink:href'引用了一个独立的图像资源,例如 JPEG、PNG 或 SVG 文件,那么图像资源将根据'image'元素的行为进行渲染;否则,根据“use”元素的行为呈现引用的资源。在任何一种情况下,当前用户坐标系都取决于“filter”元素上的“ primitiveUnits”属性值。
use而不是image对我来说看起来不错,但我不确定在这种情况下如何定义矩形区域。的文档use似乎表明,在这种情况下(引用的元素既不是 asymbol也不是svg元素),width和height属性无关紧要,但这如何描述矩形区域?我还认为,也许改变原始单位会有所帮助。或者在symbol. 所以我的第二次尝试是以下一次:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1" width="512" height="512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<symbol viewBox="0 0 100 100" id="waveImg" preserveAspectRatio="none">
<rect width="100" height="100" stroke="none" fill="url(#waveFill)"/>
</symbol>
<filter id="waveFilter" primitiveUnits="objectBoundingBox">
<feImage xlink:href="#waveImg" x="0" y="0" width="100%" height="100%"
preserveAspectRatio="none" result="waves"/>
<!-- feSpecularLighting and so on will be added later on -->
<feComposite operator="atop" in="waves" in2="SourceImage"/>
</filter>
</defs>
<g transform="translate(256 256)">
<!-- use xlink:href="#waveImg"/ works -->
<ellipse rx="200" ry="100" fill="#0000ff" stroke="none"
style="filter:url(#waveFilter)"/>
<ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/>
</g>
</svg>
Run Code Online (Sandbox Code Playgroud)
仍然没有图像可见。我究竟做错了什么?
如何将我的 SVG 文件片段用作照明的凹凸贴图,而不将其用作SourceGraphic我的过滤器?
此图像不适用于 Web 部署,但会在本地进行光栅化。所以浏览器兼容性不是什么大问题;如果这件事在 Inkscape 或 rsvg-convert 下正确呈现,那对我来说就足够了。
这可能行不通的原因有很多。
这是一个使用您的方法在 Chrome(可能还有 Safari)中运行的版本。
<svg version="1.1" width="512px" height="512px" viewbox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"> <defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<rect id="waveImg" width="100%" height="100%" stroke="none" fill="url(#waveFill)"/>
<filter id="waveFilter" primitiveUnits="objectBoundingBox">
<feImage xlink:href="#waveImg" x="0%" y="0%" width="100%" height="100%" result="waves"/>
<!-- feSpecularLighting and so on will be added later on -->
<feComposite operator="atop" in="waves" in2="SourceGraphic"/>
</filter>
</defs>
<g transform="translate(256 256)">
<ellipse rx="200" ry="100" fill="#0000ff" stroke="none"
filter="url(#waveFilter)"/>
<ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/> </g> </svg>
Run Code Online (Sandbox Code Playgroud)
然而,这在 Firefox 中不起作用,因为不支持 feImage 的对象输入,并且根据我的测试,feImage 单元在 IE 中存在相当多的错误。
您没有理由不能重复使用源图形来实现灯光效果 - 这是您尝试执行的操作的较短版本,它可以跨浏览器工作并避免 feImage。
<svg version="1.1" x="0px" y="0px" width="512px" height="512px" viewbox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"> <defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<filter id="waveFilter" x="0%" y="0%" width="100%" height="100%">
<feFlood flood-color="#0000ff" result="blue"/>
<feComposite operator="in" in2="SourceGraphic" in="blue"/>
</filter>
</defs>
<g transform="translate(256 256)">
<!-- use xlink:href="#waveImg"/ works -->
<ellipse rx="200" ry="100" fill="url(#waveFill)" filter="url(#waveFilter)"/>
<ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/> </g> </svg>
Run Code Online (Sandbox Code Playgroud)
并且(因为为什么不)这是一个添加了镜面照明的示例:
<svg version="1.1" x="0px" y="0px" width="512px" height="512px" viewbox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="waveFill" r="5%" spreadMethod="reflect">
<stop offset="0%" stop-opacity="1.00"/>
<stop offset="20%" stop-opacity="0.90"/>
<stop offset="40%" stop-opacity="0.65"/>
<stop offset="60%" stop-opacity="0.35"/>
<stop offset="80%" stop-opacity="0.10"/>
<stop offset="100%" stop-opacity="0.00"/>
</radialGradient>
<filter id="waveFilter" x="0%" y="0%" width="100%" height="100%">
<feFlood flood-color="#0000ff" result="blue"/>
<feComposite operator="in" in2="SourceGraphic" in="blue"
result="sourcewithblue"/>
<feSpecularLighting in="SourceAlpha" result="specOut"
specularConstant="2" specularExponent="20" lighting-color="white"
surfaceScale="2">
<fePointLight x="-200" y="-200" z="200"/>
</feSpecularLighting>
<feComposite operator="arithmetic" in="specOut" in2="sourcewithblue" k1="0" k2="1" k3="1" result="unclippedoutput"/>
<feComposite operator="in" in="unclippedoutput" in2="SourceGraphic"/>
</filter>
</defs>
<g transform="translate(256 256)">
<ellipse rx="200" ry="100" fill="url(#waveFill)" filter="url(#waveFilter)"/>
<ellipse rx="200" ry="100" fill="none" stroke="#ff0000"/>
</g>
</svg>
Run Code Online (Sandbox Code Playgroud)