我正在尝试为旋转立方体制作动画。为此,我使用 Poly3DCollection 并使用 FuncAnimation 对其进行动画处理:
anim = animation.FuncAnimation(fig, visualize_rotation, fargs=[collection],
init_func=partial(init_func, ax, collection),
frames=360, interval=1000 / 30)
但它渲染每一帧的速度非常慢,所以我每秒只能得到几帧。为了修复它,我尝试添加参数blit=True
希望它能提高渲染速度,但这样我就看不到立方体了。
This is what I see in the window:
Weirdly enough the cube is visible when saving the figure. This is the result I get:
我确定visualize_rotation
返回艺术家列表[collection]
这是由blit=True
如中所述这个问题 https://stackoverflow.com/questions/35068396/matplotlib-funcanimation-error-when-blit-true,但立方体仍然不可见。
那么,我该如何使用blit
在这种情况下标记,同时能够在动画期间看到立方体?
完整代码:
import math
from functools import partial
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
def visualize_rotation(frame, collection):
angle = math.radians(2) * frame
points = np.array([[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
[-1, -1, 1],
[1, -1, 1],
[1, 1, 1],
[-1, 1, 1]])
Z = np.zeros((8, 3))
for i in range(8):
Z[i, :] = [
math.cos(angle) * points[i, 0] - math.sin(angle) * points[i, 1],
math.sin(angle) * points[i, 0] + math.cos(angle) * points[i, 1],
points[i, 2]
]
Z = 10.0 * Z
# list of sides' polygons of figure
vertices = [[Z[0], Z[1], Z[2], Z[3]],
[Z[4], Z[5], Z[6], Z[7]],
[Z[0], Z[1], Z[5], Z[4]],
[Z[2], Z[3], Z[7], Z[6]],
[Z[1], Z[2], Z[6], Z[5]],
[Z[4], Z[7], Z[3], Z[0]]]
# plot sides
collection.set_verts(vertices)
print(frame)
return [collection]
def init_func(ax, collection):
ax.set_xlim(-15, 15)
ax.set_ylim(-15, 15)
ax.set_zlim(-15, 15)
ax.set_box_aspect(np.ptp([ax.get_xlim(), ax.get_ylim(), ax.get_zlim()], axis=1))
return [collection]
def animate_rotation():
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d', proj_type='persp')
collection = Poly3DCollection([[np.zeros(3)]], facecolors='white',
linewidths=1, edgecolors='r', alpha=0.8)
ax.add_collection3d(collection)
# noinspection PyUnusedLocal
anim = animation.FuncAnimation(fig, visualize_rotation, fargs=[collection],
init_func=partial(init_func, ax, collection),
frames=360, interval=1000 / 30, blit=True)
plt.show()
Edit:
我添加了每秒帧数的计算并绘制了它:
timestamps = []
def visualize_rotation(frame, collection):
...
# plot sides
collection.set_verts(vertices)
global timestamps
timestamps.append(time.time())
print(round(1 / np.mean(np.diff(timestamps[-1000:])), 1))
return [collection]
def animate_rotation():
...
plt.plot(np.diff(timestamps))
plt.ylim([0, 0.1])
plt.show()
This is what happens when the window is in normal size and the drawing speed is slow (time in seconds vs frame number):
And this is the plot when the window is tiny:
The start of the plot shows resizing of the window. Only 2 frames were dropped (at about 50 and 150) in the second case, and the overall frame rate is about 30 fps as desired. I'm looking for the same kind of behavior when the window is normally sized. When I turn blit
on, the plot looks fine, but the problem is that the cube is not visible.