如何使用 FuncAnimation 和 blit=True 为 Poly3DCollection 制作动画?

2024-02-13

我正在尝试为旋转立方体制作动画。为此,我使用 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: enter image description here

Weirdly enough the cube is visible when saving the figure. This is the result I get: enter image description here

我确定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): missing frames

And this is the plot when the window is tiny: normal framerate

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. enter image description here


我为您找到了一个简单的修复方法:在更新顶点后添加 do_3d_projection。

...
# plot sides
collection.set_verts(vertices)
collection.do_3d_projection(collection.axes.get_figure().canvas.get_renderer())
print(frame)

return [collection]

当 blit=True 时,底层代码中不会调用它,这可能是一个错误。

另外,另一个错误也出现了;当动画以 blit=True 模式重复时,最后一帧会以某种方式被保留。要解决此问题,请在 init_func 中添加 ax.clear() 和 ax.add_collection3d() :

def init_func(ax, collection):
    ax.clear()
    ax.add_collection3d(collection)
    ax.set_xlim(-15, 15)
    ax.set_ylim(-15, 15)
    ...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 FuncAnimation 和 blit=True 为 Poly3DCollection 制作动画? 的相关文章

随机推荐