feDiffuseLighting 用于模拟漫反射光照.
它利用输入图像的 Alpha 通道(透明度)来模拟光照效果, 其中
滤镜会根据这些高低起伏以及你设置的光源位置来计算哪里亮、哪里暗, 从而模拟出立体感. 或者 3D 的浮雕质感.
他的参数如下:
in:输入图像, 通常是 SourceGraphic 或者 BackgroundImagesurfaceScale:峰值高度, 默认值为 1, 取值范围为 0 到 100. 值越大, 阴影和高光越强烈, 起伏感越强diffuseConstant:漫反射系数, 默认值为 1, 取值范围为 0 到 1, 这决定了光照的整体强度和亮度lighting-color:光源颜色, 默认值为 whitefeDiffuseLighting 本身只是一个计算材质的表面, 它必须包含以下三种光源之一才能生效:
feDistantLight:平行光, 模拟太阳或灯泡等远距离光源, 由 azimuth(方位角) 和 elevation (仰角)两个角度确定方向fePointLight:点光源, 模拟灯泡等近距离光, 由 x、y、z 三个坐标确定位置feSpotLight:聚光灯, 模拟手电筒或激光等定向光源, 由 x、y、z 三个坐标确定位置, 以及 pointsAtX、pointsAtY、pointsAtZ 三个坐标确定目标位置下面这个案例中, 我们先使用 feTurbulence 生成一个噪点纹理, 然后使用 feDiffuseLighting 来模拟一个光照. 这样, 我们就能够得到一个粗糙纸张的纹理.
01export default function App() {02return (03<div className="w-full h-full flex flex-col items-center justify-center bg-gray-200 rounded-xl p-8 relative overflow-hidden">04<svg width="300" height="200" viewBox="0 0 300 200" xmlns="http://www.w3.org/2000/svg">05<defs>06<filter id="demo1-diffuse-lighting">07{/* 1. 生成基底噪音 (Turbulence) */}08<feTurbulence type="fractalNoise" baseFrequency="0.04" numOctaves="5" result="noise" />09{/* 2. 应用漫反射光照 */}10{/* lighting-color: 设置暖黄色光, 营造旧纸张感 */}11{/* surfaceScale: 设置为 2, 让纹理适度突起 */}12<feDiffuseLighting13in="noise"14surfaceScale={2}15lightingColor="#fdf5e6"16result="lightOutput"17>18{/* 使用平行光, 从左上角照射 */}19<feDistantLight azimuth={45} elevation={60} />20</feDiffuseLighting>21</filter>22</defs>2324{/* 显示结果 */}25<rect x="0" y="0" width="100%" height="100%" filter="url(#demo1-diffuse-lighting)" />26</svg>27</div>28);29}30
这个案例, 我们首先利用 feGaussianBlur 对原始图像进行高斯模糊, 它把文字的 Alpha 通道边缘变“糊”了, 然后使用 feDiffuseLighting 来模拟一个光照. 这样, 我们就能够得到一个 3D 文字效果.
01export default function App() {02return (03<div className="w-full h-full flex flex-col items-center justify-center bg-gray-900 rounded-xl p-8 relative overflow-hidden">04<svg width="400" height="150" viewBox="0 0 400 150" xmlns="http://www.w3.org/2000/svg">05<defs>06<filter id="demo2-diffuse-lighting">07{/* 1. 获取源图像的 Alpha 通道 */}08{/* 2. 使用高斯模糊平滑 Alpha 边缘 */}09{/* 如果不模糊, 边缘是垂直峭壁, 光照效果会很生硬;模糊后变成斜坡, 光照更自然 */}10<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur" />1112{/* 3. 应用光照 */}13{/* surfaceScale: 5 让文字看起来很厚 */}14<feDiffuseLighting in="blur" surfaceScale="5" lightingColor="white" result="light">15<feDistantLight azimuth="135" elevation="45" />16</feDiffuseLighting>1718{/* 4. 合成:将光照结果叠加到原始颜色上 */}19{/* 使用 arithmetic 模式:result = k1*in*in2 + k2*in + k3*in2 + k4 */}20{/* 这里主要保留了光照的阴影细节并与原色混合 */}21<feComposite22in="light"23in2="SourceGraphic"24operator="arithmetic"25k1="1"26k2="0"27k3="0"28k4="0"29/>30</filter>31</defs>32<text33x="50%"34y="50%"35textAnchor="middle"36dy=".3em"37fontFamily="Verdana"38fontWeight="bold"39fontSize="60"40fill="#4a90e2"41filter="url(#demo2-diffuse-lighting)"42>43SVG 3D44</text>45</svg>46</div>47);48}49
这个案例模拟一个黑暗房间里, 一盏灯照亮物体的效果. 这展示了 fePointLight 的威力, 以及如何利用 SVG 模拟光影衰减.
<fePointLight>. 光源被固定在画布中心上方 (x=150, y=150, z=40).<feComposite operator="multiply">. 这是关键步骤:光照图(亮处白, 暗处黑)乘以原图颜色.01export default function App() {02return (03<div className="w-full h-full flex flex-col items-center justify-center rounded-xl p-8 relative overflow-hidden">04<svg width="300" height="300" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">05<defs>06<filter id="demo3-diffuse-lighting">07{/* 1. 光照层 */}08{/* 注意:这里我们用 SourceGraphic, 假设它是一个有 alpha 变化的复杂图形 */}09{/* Z 轴位置设为 40, 模拟光源悬浮在物体上方 */}10<feDiffuseLighting11in="SourceGraphic"12surfaceScale={10}13lightingColor="#ffcc00"14result="light"15>16<fePointLight x={150} y={150} z={40} />17</feDiffuseLighting>1819{/* 2. 混合层 */}20{/* 将光照结果与原始图形混合. Multiply (正片叠底) 模式非常适合做光影 */}21{/* 只有被光照亮的地方才会显示颜色, 其他地方变暗 */}22<feComposite in="SourceGraphic" in2="light" operator="multiply" />23</filter>24</defs>2526{/* 背景:暗色 */}27<rect width="100%" height="100%" fill="#111" />2829{/* 一个复杂的图形组 */}30<g filter="url(#demo3-diffuse-lighting)">31{/* 创造一些圆圈, 模拟凸起物 */}32<circle cx="100" cy="100" r="40" fill="#44aa88" />33<circle cx="200" cy="100" r="30" fill="#cc5555" />34<circle cx="150" cy="200" r="50" fill="#4488aa" />35<rect x="0" y="0" width="300" height="300" fill="rgba(255,255,255,0.2)" />36</g>37</svg>38</div>39)40}41