在 CImg 中实现动画循环的正确方法

The correct way to implement an animation loop in CImg

我正在尝试使用 CImg 可视化我的程序。我不想使用 OpenGL,因为我正在尝试编写一个小型渲染引擎(只是为了我自己的兴趣,而不是作业!!!)。

我想在 CImg 中创建一个动画循环。

这是我的循环。

while (!disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC()) {

    img.fill(0);                           // Set pixel values to 0 (color : black)
    img.draw_text(t%WIDTH,30,"Hello World",purple); // Draw a purple "Hello world" at coordinates (100,100).

    img.draw_text(10,10, ( "Time used for rendering :: " + std::to_string( 1.0 / ( duration.count()/cnt/1000000.0 ) ) ).c_str(), purple);

    disp.render(img);
    disp.paint();

    if (t % (int)cnt == 0) {
        tmp = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(tmp - start);
        start = std::chrono::high_resolution_clock::now();
    }
    t++;

}

它工作正常,但帧率非常不稳定(范围从 100fps 到 380 fps)。这是正常的吗?或者,这是在CImg中构建动画循环的正确方法吗?

我看了CImg的文档,里面说

Should not be used for common CImgDisplay uses, since display() is more useful.

但是当我这样说的时候,

while (!disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC()) {

    img.fill(0);                           // Set pixel values to 0 (color : black)
    img.draw_text(t%WIDTH,30,"Hello World",purple); // Draw a purple "Hello world" at coordinates (100,100).

    img.draw_text(10,10, ( "Time used for rendering :: " + std::to_string( 1.0 / ( duration.count()/cnt/1000000.0 ) ) ).c_str(), purple);

    disp.display(img);

    if (t % (int)cnt == 0) {
        tmp = std::chrono::high_resolution_clock::now();
        duration = std::chrono::duration_cast<std::chrono::microseconds>(tmp - start);
        start = std::chrono::high_resolution_clock::now();
    }
    t++;

}

这个 FPS 下降到 11。那么,出了什么问题?

提前致谢。

~~~~~~~~~~~~~~~~~~~~~~我是一线~~~~~~~~~~~~~~~~~~~ ~~~~

编辑 1:

    //
    //  main.cpp
    //  Render Engine
    //
    //  Created by Ip Daniel on 6/4/18.
    //  Copyright © 2018 Ip Daniel. All rights reserved.
    //

    #include "CImg.h"
    #include <chrono>
    #include <string>
    #include <iostream>

    using namespace cimg_library;

    #define WIDTH 640
    #define HEIGHT 480

    time_t start_time;
    time_t tmp;
    double time_passed = 0;

    int main() {

        CImg<unsigned char> img(WIDTH,HEIGHT,1,3);  // Define a 640x400 color image with 8 bits per color component.
        CImgDisplay disp(img,"My Hello World Loop");
        unsigned int t = 0;
        double cnt = 30;

        auto start = std::chrono::high_resolution_clock::now();
        auto tmp = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(tmp - start);

        unsigned char purple[] = { 255,0,255 };        // Define a purple color

        while (!disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC()) {

            img.fill(0);                           // Set pixel values to 0 (color : black)
            img.draw_text(t%WIDTH,30,"Hello World",purple); // Draw a purple "Hello world" at coordinates (100,100).

            img.draw_text(10,10, ( "Time used for rendering :: " + std::to_string( 1.0 / ( duration.count()/cnt/1000000.0 ) ) ).c_str(), purple);

    //      disp.display(img);

            disp.render(img);
            disp.paint();

            if (t % (int)cnt == 0) {
                tmp = std::chrono::high_resolution_clock::now();
                duration = std::chrono::duration_cast<std::chrono::microseconds>(tmp - start);
                start = std::chrono::high_resolution_clock::now();
            }


            t++;
        }

        return 0;
    }

编译命令是

g++ -o main main.cpp -O2 -lm -lpthread -I/usr/X11R6/include -L/usr/X11R6/lib -lm -lpthread -lX11

感谢您添加代码和环境。我一直在试验您的代码,但我不确定我是否真的理解问题所在 - 无论是渲染时间的变化还是其他原因。总之,评论有点多所以我做了一个回答,大家可以再讨论一下。

基本上,我真的认为在 multi-user 操作系统上期望与 X11 服务器交互的程序具有确定性是不合理的 - 其次,我也不是当然重要。

我稍微更改了您的代码以测量 100 帧的时间,在我的机器上它在 20,000 微秒和 150,000 微秒之间变化,平均值相当一致地在 80,000 微秒左右。所以这是 100 帧的平均 80 毫秒,或每帧 0.8 毫秒,每帧 0.2-1.5 毫秒的范围。

对于流畅的动画,您需要 25-30 fps,即每帧 33-40 毫秒。所以你的渲染时间大约是每 30 毫秒发生一次 0.8 毫秒,或者你的帧时间的 2-3%,最坏的情况只有 5%(30 毫秒帧上 1.5 毫秒)。

所以,我认为您的代码更有可能拥有所需的帧,并且能够在需要渲染之前平均 wait/sleep 24 毫秒,因此您将有充足的时间和 0.8 -1.5 毫秒的变化在 30 毫秒的帧速率中不会引起注意。