如何优化 Pygame 中 3D 顶点的显示与动画?
数据小陈
结论
先调整游戏循环结构。当前代码处理每个顶点时都会调用 pygame.display.flip() 和 time.sleep(dt),还会重复读取按键状态,并对同一个顶点调用两次 project()。这些操作会随顶点数量增加,容易造成卡顿和帧率异常。
dt = 1/fps 只是固定的时间间隔,不能加快逐顶点绘制和等待。通常每帧读取一次输入,更新所有顶点并绘制完整画面,最后再刷新屏幕一次。
把刷新和等待移到顶点循环外
可以按下面的结构整理主循环。animate_vertex 仅作示意,需要根据现有 animate 的参数和返回值调整。如果动画不需要时间参数,也可以删掉 elapsed。
clock = pygame.time.Clock()
running = True
elapsed = 0.0
while running:
dt = clock.tick(60) / 1000.0
elapsed += dt
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
angle = 0.0
if keys[pygame.K_RIGHT]:
angle += 2 * dt
if keys[pygame.K_LEFT]:
angle -= 2 * dt
screen.fill((0, 0, 0))
for i, vertex in enumerate(base_vertices):
point = animate_vertex(vertex, elapsed)
if angle:
point = rotate_3d(point, [0, angle, 0])
screen_pos = project(point)
pygame.draw.circle(screen, (0, 160, 20), screen_pos, 2)
pygame.display.flip()
pygame.quit()
这里假设 base_vertices 保存导入后的原始顶点,动画和旋转都从这些顶点计算。如果每帧都基于上一帧的结果修改 vertices,旋转可能逐帧累积。是否适用要看现有动画逻辑。若动画本来就依赖上一帧状态,应保留原有状态更新方式,再测量计算开销。
减少每帧重复工作
- 每帧只读取一次按键。示例代码会在每个顶点上重复调用
pygame.key.get_pressed()。读取一次后,根据按键状态计算本帧的旋转角度即可。 - 每个顶点只投影一次。原代码绘制圆点和文字时,分别调用
project(vertices[i])。如果还要显示索引,可以复用screen_pos。 - 减少逐顶点文字渲染。
font.render(str(i), ...)会在每帧为每个顶点创建文字表面,开销可能较大。调试时可以只显示少量标签;如果标签文本固定,也可以缓存渲染后的表面。 - 根据需要减少顶点数量或绘制细节。模型包含大量顶点时,降低导入模型的细节,或只绘制部分顶点,都能减少更新、投影和绘制次数。
检查循环顺序和计时
每帧先清屏,再绘制当前帧的内容,最后调用一次 pygame.display.flip()。如果每画完一个顶点就刷新并等待,顶点越多,一帧内重复等待的次数也越多。pygame.time.Clock().tick(60) 可以限制循环帧率,并根据实际经过的时间计算 dt。
优化后如果仍然卡顿,可以分别统计动画计算、project() 和绘制所花的时间,找出主要耗时环节。仅凭这段代码无法判断 .obj 模型有多少顶点,也无法确定瓶颈是否只在渲染。顶点数量较少时,耗时也可能来自 animate 或 rotate_3d 的实现。
备注:内容仅供参考。
