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 来模拟一个光照。这样,我们就能够得到一个粗糙纸张的纹理。
10export default function App() {20return (30<div className="w-full h-full flex flex-col items-center justify-center bg-gray-200 rounded-xl p-8 relative overflow-hidden">40<svg width="300" height="200" viewBox="0 0 300 200" xmlns="http://www.w3.org/2000/svg">50<defs>60<filter id="demo1-diffuse-lighting">70{/* 1. 生成基底噪音 (Turbulence) */}80<feTurbulence type="fractalNoise" baseFrequency="0.04" numOctaves="5" result="noise" />90{/* 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 文字效果。
10export default function App() {20return (30<div className="w-full h-full flex flex-col items-center justify-center bg-gray-900 rounded-xl p-8 relative overflow-hidden">40<svg width="400" height="150" viewBox="0 0 400 150" xmlns="http://www.w3.org/2000/svg">50<defs>60<filter id="demo2-diffuse-lighting">70{/* 1. 获取源图像的 Alpha 通道 */}80{/* 2. 使用高斯模糊平滑 Alpha 边缘 */}90{/* 如果不模糊,边缘是垂直峭壁,光照效果会很生硬;模糊后变成斜坡,光照更自然 */}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">。这是关键步骤:光照图(亮处白,暗处黑)乘以原图颜色。10export default function App() {20return (30<div className="w-full h-full flex flex-col items-center justify-center rounded-xl p-8 relative overflow-hidden">40<svg width="300" height="300" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">50<defs>60<filter id="demo3-diffuse-lighting">70{/* 1. 光照层 */}80{/* 注意:这里我们用 SourceGraphic,假设它是一个有 alpha 变化的复杂图形 */}90{/* 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