【问题标题】:SFML rendering performance issueSFML 渲染性能问题
【发布时间】:2014-06-26 19:34:03
【问题描述】:

过去一周我一直在制作游戏的核心,但我碰壁了,因为渲染根本不够好。运动很生涩,我在流泪,总的来说有很多滞后。我认为这可能不是我的游戏引擎的错,所以我用一个非常简单的游戏循环测试了渲染:

        sf::RenderWindow window(sf::VideoMode(1024, 768), "Testing");
                window.setVerticalSyncEnabled(true);
        sf::Clock clock;
        sf::Event event;
        float elapsed;
        while(window.isOpen())
        {
                elapsed += clock.restart().asSeconds();
                std::cout << 1.f/elapsed << std::endl;
                while(elapsed > 1.f/60.f)
                {
                        while(window.pollEvent(event))
                        {
                                if (event.type == sf::Event::Closed || event.key.code == sf::Keyboard::Escape)
                                {
                                        window.close();
                                }
                        }
                        elapsed -= 1.f/60.f;
                }
                window.clear();
                window.display();
        }

fps 从 40 开始,上升到 60,然后回落到 30,它再次递增并重复。如果我将 VSynct 设置为 false,我会得到 30-500 fps 之间的任何地方。要么我没有正确测试帧速率,要么我的 nvidia 驱动程序有问题(我确实重新安装了 2 次,没有任何更改)。任何帮助表示赞赏!

【问题讨论】:

标签: c++ sfml frame-rate game-loop


【解决方案1】:

你给我指出了一个与你的代码相似的材料,但你写的不同。

来自:gameprogrammingpatterns.com/game-loop.html

double previous = getCurrentTime();
double lag = 0.0;
while (true)
{
  double current = getCurrentTime();
  double elapsed = current - previous;
  previous = current;
  lag += elapsed;

  processInput();

  while (lag >= MS_PER_UPDATE)
  {
    update();
    lag -= MS_PER_UPDATE;
  }

  render();
}

您似乎对elapsedlag 都使用了一个变量elapsed。这就是让我感到困惑的地方。您对elapsed 的修改使其无法用于测量时间。我认为您的代码应该看起来更像:

    sf::RenderWindow window(sf::VideoMode(1024, 768), "Testing");
            window.setVerticalSyncEnabled(true);
    sf::Clock clock;
    sf::Event event;
    float lag;
    float elapsed;

    while(window.isOpen())
    {
            lag = elapsed = clock.restart().asSeconds();
            std::cout << 1.f/elapsed << std::endl;
            while(lag > 1.f/60.f)
            {
                    while(window.pollEvent(event))
                    {
                            if (event.type == sf::Event::Closed || event.key.code == sf::Keyboard::Escape)
                            {
                                    window.close();
                            }
                    }
                    lag -= 1.f/60.f;
            }
            window.clear();
            window.display();
    }

我仍然不确定这是否正确。我不知道clock.restart().asSeconds() 到底做了什么。就个人而言,我会像示例一样逐行实现它。为什么要重新设计工作代码?

编辑:OP 确认,使用 elapsed 进行“节流”会破坏其作为时间测量变量的目的。

【讨论】:

  • restart() 函数返回经过的时间,因此我不必使用滞后变量。然而,它确实不能正确地计算这样的帧数,我完全错过了这一点。我现在一直保持 60 fps,非常感谢!
  • 所以我猜对了,是的。感谢您的确认。我不确定是否正确,因为您使用 += 和 elapsed,但我认为如果 restart 真的重新启动时钟,则不需要总结。
【解决方案2】:

这就是我认为正在发生的事情。如果我正确理解您的代码,您希望保持模拟的时间步长不变 - 每秒 60 次。您正在使用一种累加器来跟踪您应该运行循环的次数。使用这样的累加器时的问题是您必须记住您的模拟循环需要时间。为了说明为什么这可能是一个问题,让我们检查一些案例。为了清楚起见,我将使用 20 毫秒而不是 16.6666(1/60 秒)作为时间步长。假设:

  1. 您的模拟循环需要 10 毫秒才能运行。第一次elapsed &gt;= 20,它被重置并运行你的模拟循环。下次你回到顶部时,elapsed == 10 + c 其中c 是一些小东西,它会跳过。最终,elapsed &gt;= 20 再次重复。一切都很好。
  2. 您的模拟循环运行时间正好为 20 毫秒。 elapsed 达到 20,内部循环需要 20 毫秒才能运行。下次您运行循环时,elapsed == 20。它重复。一切基本都很好。
  3. 您的模拟循环需要 40 毫秒才能运行。当elapsed 达到 20 时,内部循环运行,耗时 40 毫秒。然后,外部循环再次运行,这次是elapsed == 40。然后,内部循环运行两次,耗时 80 毫秒。 elapsed 现在是 80。内部循环运行 4 次,耗时 160 毫秒。 elapsed 现在是 160。内部循环运行 8 次,耗时 320 毫秒……以此类推。

当然,模拟循环所花费的时间永远不会像这些示例中那样恒定,但想法是相同的。如果您可以假设循环永远不会比您的模拟步骤花费更多的时间来运行,那很好。一旦运行循环的时间超过1/60th 秒,您就会开始获得一种反馈循环,其中外部循环的完成时间越来越长。

我解决“与帧速率相关的运动”这类问题的常用方法是将增量时间传递给我拥有的所有 update() 类型的函数,无论它们在哪里。然后,所有的移动/攻击/任何东西都取决于那个增量。例如,对于运动,我会有这样的东西:

const static pixelsPerSecond = 100
update(float delta) { //delta is seconds
    x += moveX * pixelsPerSecond * delta;
    y += moveY * pixelsPerSecond * delta;
}

编辑:刚刚看到您在上面发布的链接,其中提到了我建议的可变时间步长的缺点。不过,总的来说,如果您不进行精确的物理模拟或多人游戏,它应该可以正常工作。 (有趣的是,您的链接包含指向Glenn Fielder's article 的链接,其中还提到了我上面描述的“死亡螺旋”。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-07
    • 2020-05-02
    • 2012-04-09
    • 2012-06-05
    • 2015-07-18
    • 2021-01-30
    相关资源
    最近更新 更多