1概述

feDiffuseLighting 用于模拟漫反射光照。

它利用输入图像的 Alpha 通道(透明度)来模拟光照效果,其中

  • Alpha = 1: 表示高处,光照强度最大
  • Alpha = 0: 表示低处,光照强度最小
  • Alpha = 0.5(中间值): 表示中间位置,处于斜坡,光照强度为中间值

滤镜会根据这些高低起伏以及你设置的光源位置来计算哪里亮、哪里暗,从而模拟出立体感。或者 3D 的浮雕质感。

他的参数如下:

  • in:输入图像,通常是 SourceGraphic 或者 BackgroundImage
  • surfaceScale:峰值高度,默认值为 1,取值范围为 0 到 100。值越大,阴影和高光越强烈,起伏感越强
  • diffuseConstant:漫反射系数,默认值为 1,取值范围为 0 到 1,这决定了光照的整体强度和亮度
  • lighting-color:光源颜色,默认值为 white

feDiffuseLighting 本身只是一个计算材质的表面,它必须包含以下三种光源之一才能生效:

  • feDistantLight:平行光,模拟太阳或灯泡等远距离光源,由 azimuth(方位角) 和 elevation (仰角)两个角度确定方向
  • fePointLight:点光源,模拟灯泡等近距离光,由 xyz 三个坐标确定位置
  • feSpotLight:聚光灯,模拟手电筒或激光等定向光源,由 xyz 三个坐标确定位置,以及 pointsAtXpointsAtYpointsAtZ 三个坐标确定目标位置

2案例:粗糙纹理生成

下面这个案例中,我们先使用 feTurbulence 生成一个噪点纹理,然后使用 feDiffuseLighting 来模拟一个光照。这样,我们就能够得到一个粗糙纸张的纹理。

预览
index.tsx
1
export default function App() {
2
return (
3
<div className="w-full h-full flex flex-col items-center justify-center bg-gray-200 rounded-xl p-8 relative overflow-hidden">
4
<svg width="300" height="200" viewBox="0 0 300 200" xmlns="http://www.w3.org/2000/svg">
5
<defs>
6
<filter id="demo1-diffuse-lighting">
7
{/* 1. 生成基底噪音 (Turbulence) */}
8
<feTurbulence type="fractalNoise" baseFrequency="0.04" numOctaves="5" result="noise" />
9
{/* 2. 应用漫反射光照 */}
10
{/* lighting-color: 设置暖黄色光,营造旧纸张感 */}
11
{/* surfaceScale: 设置为 2,让纹理适度突起 */}
12
<feDiffuseLighting
13
in="noise"
14
surfaceScale={2}
15
lightingColor="#fdf5e6"
16
result="lightOutput"
17
>
18
{/* 使用平行光,从左上角照射 */}
19
<feDistantLight azimuth={45} elevation={60} />
20
</feDiffuseLighting>
21
</filter>
22
</defs>
23
24
{/* 显示结果 */}
25
<rect x="0" y="0" width="100%" height="100%" filter="url(#demo1-diffuse-lighting)" />
26
</svg>
27
</div>
28
);
29
}
30

3案例:3D 文字效果

这个案例,我们首先利用 feGaussianBlur 对原始图像进行高斯模糊,它把文字的 Alpha 通道边缘变“糊”了,然后使用 feDiffuseLighting 来模拟一个光照。这样,我们就能够得到一个 3D 文字效果。

预览
index.tsx
1
export default function App() {
2
return (
3
<div className="w-full h-full flex flex-col items-center justify-center bg-gray-900 rounded-xl p-8 relative overflow-hidden">
4
<svg width="400" height="150" viewBox="0 0 400 150" xmlns="http://www.w3.org/2000/svg">
5
<defs>
6
<filter id="demo2-diffuse-lighting">
7
{/* 1. 获取源图像的 Alpha 通道 */}
8
{/* 2. 使用高斯模糊平滑 Alpha 边缘 */}
9
{/* 如果不模糊,边缘是垂直峭壁,光照效果会很生硬;模糊后变成斜坡,光照更自然 */}
10
<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur" />
11
12
{/* 3. 应用光照 */}
13
{/* surfaceScale: 5 让文字看起来很厚 */}
14
<feDiffuseLighting in="blur" surfaceScale="5" lightingColor="white" result="light">
15
<feDistantLight azimuth="135" elevation="45" />
16
</feDiffuseLighting>
17
18
{/* 4. 合成:将光照结果叠加到原始颜色上 */}
19
{/* 使用 arithmetic 模式:result = k1*in*in2 + k2*in + k3*in2 + k4 */}
20
{/* 这里主要保留了光照的阴影细节并与原色混合 */}
21
<feComposite
22
in="light"
23
in2="SourceGraphic"
24
operator="arithmetic"
25
k1="1"
26
k2="0"
27
k3="0"
28
k4="0"
29
/>
30
</filter>
31
</defs>
32
<text
33
x="50%"
34
y="50%"
35
textAnchor="middle"
36
dy=".3em"
37
fontFamily="Verdana"
38
fontWeight="bold"
39
fontSize="60"
40
fill="#4a90e2"
41
filter="url(#demo2-diffuse-lighting)"
42
>
43
SVG 3D
44
</text>
45
</svg>
46
</div>
47
);
48
}
49

4案例:点光源照射

这个案例模拟一个黑暗房间里,一盏灯照亮物体的效果。这展示了 fePointLight 的威力,以及如何利用 SVG 模拟光影衰减。

  • 这里使用了 <fePointLight>。光源被固定在画布中心上方 (x=150, y=150, z=40)。
  • 使用了 <feComposite operator="multiply">。这是关键步骤:光照图(亮处白,暗处黑)乘以原图颜色。
  • 结果:光源正下方的物体最亮,远离中心的物体逐渐隐入黑暗,非常有氛围感。
预览
index.tsx
1
export default function App() {
2
return (
3
<div className="w-full h-full flex flex-col items-center justify-center rounded-xl p-8 relative overflow-hidden">
4
<svg width="300" height="300" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
5
<defs>
6
<filter id="demo3-diffuse-lighting">
7
{/* 1. 光照层 */}
8
{/* 注意:这里我们用 SourceGraphic,假设它是一个有 alpha 变化的复杂图形 */}
9
{/* Z 轴位置设为 40,模拟光源悬浮在物体上方 */}
10
<feDiffuseLighting
11
in="SourceGraphic"
12
surfaceScale={10}
13
lightingColor="#ffcc00"
14
result="light"
15
>
16
<fePointLight x={150} y={150} z={40} />
17
</feDiffuseLighting>
18
19
{/* 2. 混合层 */}
20
{/* 将光照结果与原始图形混合。Multiply (正片叠底) 模式非常适合做光影 */}
21
{/* 只有被光照亮的地方才会显示颜色,其他地方变暗 */}
22
<feComposite in="SourceGraphic" in2="light" operator="multiply" />
23
</filter>
24
</defs>
25
26
{/* 背景:暗色 */}
27
<rect width="100%" height="100%" fill="#111" />
28
29
{/* 一个复杂的图形组 */}
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
专栏首页
到顶
专栏目录