使用 SVG 制作逼真的(正弦曲线)旗帜动画/颤动
Making realistic (sinusoid) flag animation / flutter with SVG
我正在尝试制作一个更逼真的动画 svg
旗帜在风中飘扬。这是我目前正在使用的一个简单的旗帜基地:
<svg
xmlns="http://www.w3.org/2000/svg"
width="200px"
height="100px"
viewBox="0 0 200 100"
>
<path
fill="red"
d=
"
M 20,20
Q 25,10 50,20
T 80,20
L 80,80
Q 75,90 50,80
T 20,80
z
"
>
<animate
dur="1.8s"
attributeName="d"
fill="freeze"
repeatCount="indefinite"
values=
"
M 20,20
Q 25,10 50,20
T 80,20
L 80,80
Q 75,90 50,80
T 20,80
z;
M 20,30
Q 35,30 50,20
T 80,20
L 80,80
Q 65,70 50,80
T 20,90
z;
M 20,20
Q 25,10 50,20
T 80,20
L 80,80
Q 75,90 50,80
T 20,80
z;
"
calcMode="spline"
keySplines="0,0,.58,1; 0,0,.58,1"
/>
</path>
<line x1="50" y1="35" x2="50" y2="65" stroke="#fff" stroke-width="10" />
<line x1="35" y1="50" x2="65" y2="50" stroke="#fff" stroke-width="10" />
</svg>
如您所见,我绘制了一个正方形,其顶部和底部边缘有一个额外的中点。为了让我当前的旗帜动起来,我移动了左边缘的角点和中点的曲率,但这并没有提供很好的 "flag behaviour".
我很想实现更令人信服的颤动,类似于从右到左的正弦曲线。我已经尝试将中点设置为 "flow" 到左边缘的动画,因为它们会改变曲率角度,但这看起来也不正确。
我认为仅通过动画两个端点和两个关键帧之间的控制点是不可能获得令人满意的结果的。在任何情况下,如果旗帜看起来像是固定在旗杆上,旗帜的一侧应该保持不动。
我认为最好的方法是使用更多的控制点和更多的关键帧以编程方式生成路径数据。这是我在 Python (v2) 中制作的一个程序来演示:
def flag_transform(x, y, t, a):
from math import sin, pi
freq = 1.0
theta = (x * freq - t) * 2 * pi
amp = a * x
return (x, y+amp*sin(theta))
def flag_svg(nframes):
x0 = y0 = 20
w = h = 160
amp = 10.0
frames = []
for i in range(nframes):
s = 'M%.1f %.1f' % (x0,y0)
for x in range(1,11):
(fx1,fy1) = flag_transform(x*0.1-.05,0,i*1.0/nframes,amp)
ax = fx1 * w + x0
ay = fy1 + y0
(fx2,fy2) = flag_transform(x*0.1,0,i*1.0/nframes,amp)
bx = fx2 * w + x0
by = fy2 + y0
s += 'Q%.1f %.1f %.1f %.1f' % (ax,ay,bx,by)
by += h
s += 'L%.1f %.1f' % (bx,by)
for x in range(9,-1,-1):
(fx1,fy1) = flag_transform(x*0.1+.05,0,i*1.0/nframes,amp)
ax = fx1 * w + x0
ay = fy1 + y0 + h
(fx2,fy2) = flag_transform(x*0.1,0,i*1.0/nframes,amp)
bx = fx2 * w + x0
by = fy2 + y0 + h
s += 'Q%.1f %.1f %.1f %.1f' % (ax,ay,bx,by)
s += 'Z'
frames.append(s.replace('.0',''))
#
frames.append(frames[0])
print '<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px" viewBox="0 0 200 200">'
print '<path fill="red" d="' + frames[0] + '">'
print '<animate dur="1.8s" attributeName="d" fill="freeze" repeatCount="indefinite" values="'
print ';\n'.join(frames)
print '"/>'
print '</path>'
print '</svg>'
flag_svg(10)
这是输出。如果你想模拟瑞士国旗,你可以用完全相同的方式在中间添加白色十字。水平线使用二次曲线(Q
),垂直线使用直线(L
)。
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px" viewBox="0 0 200 200">
<path fill="red" d="M20 20Q28 20.2 36 20.6Q44 21.2 52 21.9Q60 22.5 68 22.9Q76 22.8 84 22.4Q92 21.4 100 20Q108 18.3 116 16.5Q124 14.7 132 13.3Q140 12.5 148 12.4Q156 13.1 164 14.7Q172 17.1 180 20L180 180Q172 177.1 164 174.7Q156 173.1 148 172.4Q140 172.5 132 173.3Q124 174.7 116 176.5Q108 178.3 100 180Q92 181.4 84 182.4Q76 182.8 68 182.9Q60 182.5 52 181.9Q44 181.2 36 180.6Q28 180.2 20 180Z">
<animate dur="1.8s" attributeName="d" fill="freeze" repeatCount="indefinite" values="
M20 20Q28 20.2 36 20.6Q44 21.2 52 21.9Q60 22.5 68 22.9Q76 22.8 84 22.4Q92 21.4 100 20Q108 18.3 116 16.5Q124 14.7 132 13.3Q140 12.5 148 12.4Q156 13.1 164 14.7Q172 17.1 180 20L180 180Q172 177.1 164 174.7Q156 173.1 148 172.4Q140 172.5 132 173.3Q124 174.7 116 176.5Q108 178.3 100 180Q92 181.4 84 182.4Q76 182.8 68 182.9Q60 182.5 52 181.9Q44 181.2 36 180.6Q28 180.2 20 180Z;
M20 20Q28 19.8 36 20Q44 20.5 52 21.2Q60 22 68 22.9Q76 23.5 84 23.8Q92 23.6 100 22.9Q108 21.7 116 20Q124 18 132 15.9Q140 13.9 148 12.4Q156 11.5 164 11.4Q172 12.3 180 14.1L180 174.1Q172 172.3 164 171.4Q156 171.5 148 172.4Q140 173.9 132 175.9Q124 178 116 180Q108 181.7 100 182.9Q92 183.6 84 183.8Q76 183.5 68 182.9Q60 182 52 181.2Q44 180.5 36 180Q28 179.8 20 180Z;
M20 20Q28 19.6 36 19.4Q44 19.5 52 20Q60 20.8 68 21.8Q76 22.8 84 23.8Q92 24.5 100 24.8Q108 24.4 116 23.5Q124 22 132 20Q140 17.7 148 15.3Q156 13.1 164 11.4Q172 10.5 180 10.5L180 170.5Q172 170.5 164 171.4Q156 173.1 148 175.3Q140 177.7 132 180Q124 182 116 183.5Q108 184.4 100 184.8Q92 184.5 84 183.8Q76 182.8 68 181.8Q60 180.8 52 180Q44 179.5 36 179.4Q28 179.6 20 180Z;
M20 20Q28 19.5 36 19Q44 18.8 52 18.8Q60 19.2 68 20Q76 21.1 84 22.4Q92 23.6 100 24.8Q108 25.5 116 25.7Q124 25.3 132 24.1Q140 22.3 148 20Q156 17.4 164 14.7Q172 12.3 180 10.5L180 170.5Q172 172.3 164 174.7Q156 177.4 148 180Q140 182.3 132 184.1Q124 185.3 116 185.7Q108 185.5 100 184.8Q92 183.6 84 182.4Q76 181.1 68 180Q60 179.2 52 178.8Q44 178.8 36 179Q28 179.5 20 180Z;
M20 20Q28 19.6 36 19Q44 18.5 52 18.1Q60 18 68 18.2Q76 18.9 84 20Q92 21.4 100 22.9Q108 24.4 116 25.7Q124 26.5 132 26.7Q140 26.1 148 24.7Q156 22.6 164 20Q172 17.1 180 14.1L180 174.1Q172 177.1 164 180Q156 182.6 148 184.7Q140 186.1 132 186.7Q124 186.5 116 185.7Q108 184.4 100 182.9Q92 181.4 84 180Q76 178.9 68 178.2Q60 178 52 178.1Q44 178.5 36 179Q28 179.6 20 180Z;
M20 20Q28 19.8 36 19.4Q44 18.8 52 18.1Q60 17.5 68 17.1Q76 17.2 84 17.6Q92 18.6 100 20Q108 21.7 116 23.5Q124 25.3 132 26.7Q140 27.5 148 27.6Q156 26.9 164 25.3Q172 22.9 180 20L180 180Q172 182.9 164 185.3Q156 186.9 148 187.6Q140 187.5 132 186.7Q124 185.3 116 183.5Q108 181.7 100 180Q92 178.6 84 177.6Q76 177.2 68 177.1Q60 177.5 52 178.1Q44 178.8 36 179.4Q28 179.8 20 180Z;
M20 20Q28 20.2 36 20Q44 19.5 52 18.8Q60 18 68 17.1Q76 16.5 84 16.2Q92 16.4 100 17.1Q108 18.3 116 20Q124 22 132 24.1Q140 26.1 148 27.6Q156 28.5 164 28.6Q172 27.7 180 25.9L180 185.9Q172 187.7 164 188.6Q156 188.5 148 187.6Q140 186.1 132 184.1Q124 182 116 180Q108 178.3 100 177.1Q92 176.4 84 176.2Q76 176.5 68 177.1Q60 178 52 178.8Q44 179.5 36 180Q28 180.2 20 180Z;
M20 20Q28 20.4 36 20.6Q44 20.5 52 20Q60 19.2 68 18.2Q76 17.2 84 16.2Q92 15.5 100 15.2Q108 15.6 116 16.5Q124 18 132 20Q140 22.3 148 24.7Q156 26.9 164 28.6Q172 29.5 180 29.5L180 189.5Q172 189.5 164 188.6Q156 186.9 148 184.7Q140 182.3 132 180Q124 178 116 176.5Q108 175.6 100 175.2Q92 175.5 84 176.2Q76 177.2 68 178.2Q60 179.2 52 180Q44 180.5 36 180.6Q28 180.4 20 180Z;
M20 20Q28 20.5 36 21Q44 21.2 52 21.2Q60 20.8 68 20Q76 18.9 84 17.6Q92 16.4 100 15.2Q108 14.5 116 14.3Q124 14.7 132 15.9Q140 17.7 148 20Q156 22.6 164 25.3Q172 27.7 180 29.5L180 189.5Q172 187.7 164 185.3Q156 182.6 148 180Q140 177.7 132 175.9Q124 174.7 116 174.3Q108 174.5 100 175.2Q92 176.4 84 177.6Q76 178.9 68 180Q60 180.8 52 181.2Q44 181.2 36 181Q28 180.5 20 180Z;
M20 20Q28 20.4 36 21Q44 21.5 52 21.9Q60 22 68 21.8Q76 21.1 84 20Q92 18.6 100 17.1Q108 15.6 116 14.3Q124 13.5 132 13.3Q140 13.9 148 15.3Q156 17.4 164 20Q172 22.9 180 25.9L180 185.9Q172 182.9 164 180Q156 177.4 148 175.3Q140 173.9 132 173.3Q124 173.5 116 174.3Q108 175.6 100 177.1Q92 178.6 84 180Q76 181.1 68 181.8Q60 182 52 181.9Q44 181.5 36 181Q28 180.4 20 180Z;
M20 20Q28 20.2 36 20.6Q44 21.2 52 21.9Q60 22.5 68 22.9Q76 22.8 84 22.4Q92 21.4 100 20Q108 18.3 116 16.5Q124 14.7 132 13.3Q140 12.5 148 12.4Q156 13.1 164 14.7Q172 17.1 180 20L180 180Q172 177.1 164 174.7Q156 173.1 148 172.4Q140 172.5 132 173.3Q124 174.7 116 176.5Q108 178.3 100 180Q92 181.4 84 182.4Q76 182.8 68 182.9Q60 182.5 52 181.9Q44 181.2 36 180.6Q28 180.2 20 180Z
"/>
</path>
</svg>
我正在尝试制作一个更逼真的动画 svg
旗帜在风中飘扬。这是我目前正在使用的一个简单的旗帜基地:
<svg
xmlns="http://www.w3.org/2000/svg"
width="200px"
height="100px"
viewBox="0 0 200 100"
>
<path
fill="red"
d=
"
M 20,20
Q 25,10 50,20
T 80,20
L 80,80
Q 75,90 50,80
T 20,80
z
"
>
<animate
dur="1.8s"
attributeName="d"
fill="freeze"
repeatCount="indefinite"
values=
"
M 20,20
Q 25,10 50,20
T 80,20
L 80,80
Q 75,90 50,80
T 20,80
z;
M 20,30
Q 35,30 50,20
T 80,20
L 80,80
Q 65,70 50,80
T 20,90
z;
M 20,20
Q 25,10 50,20
T 80,20
L 80,80
Q 75,90 50,80
T 20,80
z;
"
calcMode="spline"
keySplines="0,0,.58,1; 0,0,.58,1"
/>
</path>
<line x1="50" y1="35" x2="50" y2="65" stroke="#fff" stroke-width="10" />
<line x1="35" y1="50" x2="65" y2="50" stroke="#fff" stroke-width="10" />
</svg>
如您所见,我绘制了一个正方形,其顶部和底部边缘有一个额外的中点。为了让我当前的旗帜动起来,我移动了左边缘的角点和中点的曲率,但这并没有提供很好的 "flag behaviour".
我很想实现更令人信服的颤动,类似于从右到左的正弦曲线。我已经尝试将中点设置为 "flow" 到左边缘的动画,因为它们会改变曲率角度,但这看起来也不正确。
我认为仅通过动画两个端点和两个关键帧之间的控制点是不可能获得令人满意的结果的。在任何情况下,如果旗帜看起来像是固定在旗杆上,旗帜的一侧应该保持不动。
我认为最好的方法是使用更多的控制点和更多的关键帧以编程方式生成路径数据。这是我在 Python (v2) 中制作的一个程序来演示:
def flag_transform(x, y, t, a):
from math import sin, pi
freq = 1.0
theta = (x * freq - t) * 2 * pi
amp = a * x
return (x, y+amp*sin(theta))
def flag_svg(nframes):
x0 = y0 = 20
w = h = 160
amp = 10.0
frames = []
for i in range(nframes):
s = 'M%.1f %.1f' % (x0,y0)
for x in range(1,11):
(fx1,fy1) = flag_transform(x*0.1-.05,0,i*1.0/nframes,amp)
ax = fx1 * w + x0
ay = fy1 + y0
(fx2,fy2) = flag_transform(x*0.1,0,i*1.0/nframes,amp)
bx = fx2 * w + x0
by = fy2 + y0
s += 'Q%.1f %.1f %.1f %.1f' % (ax,ay,bx,by)
by += h
s += 'L%.1f %.1f' % (bx,by)
for x in range(9,-1,-1):
(fx1,fy1) = flag_transform(x*0.1+.05,0,i*1.0/nframes,amp)
ax = fx1 * w + x0
ay = fy1 + y0 + h
(fx2,fy2) = flag_transform(x*0.1,0,i*1.0/nframes,amp)
bx = fx2 * w + x0
by = fy2 + y0 + h
s += 'Q%.1f %.1f %.1f %.1f' % (ax,ay,bx,by)
s += 'Z'
frames.append(s.replace('.0',''))
#
frames.append(frames[0])
print '<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px" viewBox="0 0 200 200">'
print '<path fill="red" d="' + frames[0] + '">'
print '<animate dur="1.8s" attributeName="d" fill="freeze" repeatCount="indefinite" values="'
print ';\n'.join(frames)
print '"/>'
print '</path>'
print '</svg>'
flag_svg(10)
这是输出。如果你想模拟瑞士国旗,你可以用完全相同的方式在中间添加白色十字。水平线使用二次曲线(Q
),垂直线使用直线(L
)。
<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px" viewBox="0 0 200 200">
<path fill="red" d="M20 20Q28 20.2 36 20.6Q44 21.2 52 21.9Q60 22.5 68 22.9Q76 22.8 84 22.4Q92 21.4 100 20Q108 18.3 116 16.5Q124 14.7 132 13.3Q140 12.5 148 12.4Q156 13.1 164 14.7Q172 17.1 180 20L180 180Q172 177.1 164 174.7Q156 173.1 148 172.4Q140 172.5 132 173.3Q124 174.7 116 176.5Q108 178.3 100 180Q92 181.4 84 182.4Q76 182.8 68 182.9Q60 182.5 52 181.9Q44 181.2 36 180.6Q28 180.2 20 180Z">
<animate dur="1.8s" attributeName="d" fill="freeze" repeatCount="indefinite" values="
M20 20Q28 20.2 36 20.6Q44 21.2 52 21.9Q60 22.5 68 22.9Q76 22.8 84 22.4Q92 21.4 100 20Q108 18.3 116 16.5Q124 14.7 132 13.3Q140 12.5 148 12.4Q156 13.1 164 14.7Q172 17.1 180 20L180 180Q172 177.1 164 174.7Q156 173.1 148 172.4Q140 172.5 132 173.3Q124 174.7 116 176.5Q108 178.3 100 180Q92 181.4 84 182.4Q76 182.8 68 182.9Q60 182.5 52 181.9Q44 181.2 36 180.6Q28 180.2 20 180Z;
M20 20Q28 19.8 36 20Q44 20.5 52 21.2Q60 22 68 22.9Q76 23.5 84 23.8Q92 23.6 100 22.9Q108 21.7 116 20Q124 18 132 15.9Q140 13.9 148 12.4Q156 11.5 164 11.4Q172 12.3 180 14.1L180 174.1Q172 172.3 164 171.4Q156 171.5 148 172.4Q140 173.9 132 175.9Q124 178 116 180Q108 181.7 100 182.9Q92 183.6 84 183.8Q76 183.5 68 182.9Q60 182 52 181.2Q44 180.5 36 180Q28 179.8 20 180Z;
M20 20Q28 19.6 36 19.4Q44 19.5 52 20Q60 20.8 68 21.8Q76 22.8 84 23.8Q92 24.5 100 24.8Q108 24.4 116 23.5Q124 22 132 20Q140 17.7 148 15.3Q156 13.1 164 11.4Q172 10.5 180 10.5L180 170.5Q172 170.5 164 171.4Q156 173.1 148 175.3Q140 177.7 132 180Q124 182 116 183.5Q108 184.4 100 184.8Q92 184.5 84 183.8Q76 182.8 68 181.8Q60 180.8 52 180Q44 179.5 36 179.4Q28 179.6 20 180Z;
M20 20Q28 19.5 36 19Q44 18.8 52 18.8Q60 19.2 68 20Q76 21.1 84 22.4Q92 23.6 100 24.8Q108 25.5 116 25.7Q124 25.3 132 24.1Q140 22.3 148 20Q156 17.4 164 14.7Q172 12.3 180 10.5L180 170.5Q172 172.3 164 174.7Q156 177.4 148 180Q140 182.3 132 184.1Q124 185.3 116 185.7Q108 185.5 100 184.8Q92 183.6 84 182.4Q76 181.1 68 180Q60 179.2 52 178.8Q44 178.8 36 179Q28 179.5 20 180Z;
M20 20Q28 19.6 36 19Q44 18.5 52 18.1Q60 18 68 18.2Q76 18.9 84 20Q92 21.4 100 22.9Q108 24.4 116 25.7Q124 26.5 132 26.7Q140 26.1 148 24.7Q156 22.6 164 20Q172 17.1 180 14.1L180 174.1Q172 177.1 164 180Q156 182.6 148 184.7Q140 186.1 132 186.7Q124 186.5 116 185.7Q108 184.4 100 182.9Q92 181.4 84 180Q76 178.9 68 178.2Q60 178 52 178.1Q44 178.5 36 179Q28 179.6 20 180Z;
M20 20Q28 19.8 36 19.4Q44 18.8 52 18.1Q60 17.5 68 17.1Q76 17.2 84 17.6Q92 18.6 100 20Q108 21.7 116 23.5Q124 25.3 132 26.7Q140 27.5 148 27.6Q156 26.9 164 25.3Q172 22.9 180 20L180 180Q172 182.9 164 185.3Q156 186.9 148 187.6Q140 187.5 132 186.7Q124 185.3 116 183.5Q108 181.7 100 180Q92 178.6 84 177.6Q76 177.2 68 177.1Q60 177.5 52 178.1Q44 178.8 36 179.4Q28 179.8 20 180Z;
M20 20Q28 20.2 36 20Q44 19.5 52 18.8Q60 18 68 17.1Q76 16.5 84 16.2Q92 16.4 100 17.1Q108 18.3 116 20Q124 22 132 24.1Q140 26.1 148 27.6Q156 28.5 164 28.6Q172 27.7 180 25.9L180 185.9Q172 187.7 164 188.6Q156 188.5 148 187.6Q140 186.1 132 184.1Q124 182 116 180Q108 178.3 100 177.1Q92 176.4 84 176.2Q76 176.5 68 177.1Q60 178 52 178.8Q44 179.5 36 180Q28 180.2 20 180Z;
M20 20Q28 20.4 36 20.6Q44 20.5 52 20Q60 19.2 68 18.2Q76 17.2 84 16.2Q92 15.5 100 15.2Q108 15.6 116 16.5Q124 18 132 20Q140 22.3 148 24.7Q156 26.9 164 28.6Q172 29.5 180 29.5L180 189.5Q172 189.5 164 188.6Q156 186.9 148 184.7Q140 182.3 132 180Q124 178 116 176.5Q108 175.6 100 175.2Q92 175.5 84 176.2Q76 177.2 68 178.2Q60 179.2 52 180Q44 180.5 36 180.6Q28 180.4 20 180Z;
M20 20Q28 20.5 36 21Q44 21.2 52 21.2Q60 20.8 68 20Q76 18.9 84 17.6Q92 16.4 100 15.2Q108 14.5 116 14.3Q124 14.7 132 15.9Q140 17.7 148 20Q156 22.6 164 25.3Q172 27.7 180 29.5L180 189.5Q172 187.7 164 185.3Q156 182.6 148 180Q140 177.7 132 175.9Q124 174.7 116 174.3Q108 174.5 100 175.2Q92 176.4 84 177.6Q76 178.9 68 180Q60 180.8 52 181.2Q44 181.2 36 181Q28 180.5 20 180Z;
M20 20Q28 20.4 36 21Q44 21.5 52 21.9Q60 22 68 21.8Q76 21.1 84 20Q92 18.6 100 17.1Q108 15.6 116 14.3Q124 13.5 132 13.3Q140 13.9 148 15.3Q156 17.4 164 20Q172 22.9 180 25.9L180 185.9Q172 182.9 164 180Q156 177.4 148 175.3Q140 173.9 132 173.3Q124 173.5 116 174.3Q108 175.6 100 177.1Q92 178.6 84 180Q76 181.1 68 181.8Q60 182 52 181.9Q44 181.5 36 181Q28 180.4 20 180Z;
M20 20Q28 20.2 36 20.6Q44 21.2 52 21.9Q60 22.5 68 22.9Q76 22.8 84 22.4Q92 21.4 100 20Q108 18.3 116 16.5Q124 14.7 132 13.3Q140 12.5 148 12.4Q156 13.1 164 14.7Q172 17.1 180 20L180 180Q172 177.1 164 174.7Q156 173.1 148 172.4Q140 172.5 132 173.3Q124 174.7 116 176.5Q108 178.3 100 180Q92 181.4 84 182.4Q76 182.8 68 182.9Q60 182.5 52 181.9Q44 181.2 36 180.6Q28 180.2 20 180Z
"/>
</path>
</svg>