GLFW关键回调同步

时间:2016-04-12 17:06:37

标签: c opengl 3d glfw

我对GLFW和OpenGL一般都很陌生,而且我正在研究小型模型渲染器。 我目前正在研究输入,我正面临着GLFW如何处理输入的问题,让我解释一下: 每个教程都告诉我们使用glfwGetKey和#34; if forest"看看是否按下了这样的钥匙。我遇到的问题是,如果我映射了很多键,它可能会变慢,加上它很难看。 所以我使用函数指针表和glfwSetKeyCallback来加快速度并使代码更清晰。 我遇到的问题是我面对的是一场看起来像是竞争的情况,相机似乎口吃了。 我使用在每个帧上计算的增量时间以获得恒定的速度。 从我所看到的情况来看,似乎每隔一段时间就调用一次关键回调函数,而当一个键重复时,每一帧都不会调用一次.... 我从他们的github使用最新版本的glfw3,我在每个循环开始时交换缓冲区并在最后使用glfwPollEvents()。

我的问题如下:有没有办法同步glfwPollEvents调用和渲染,以避免渲染循环和回调函数之间的卡顿和deltatime差异? 在此先感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

一般来说,你应该处理输入的方式是保留一个键列表,并记录它们的最后输入状态。

struct key_event {
    int key, code, action, modifiers;
    std::chrono::steady_clock::time_point time_of_event;
}

std::map<int, bool> keys;
std::queue<key_event> unhandled_keys;
void handle_key(GLFWwindow* window, int key, int code, int action, int modifiers) {
    unhandled_keys.emplace_back(key, code, action, modifiers, std::chrono::steady_clock::now());
}

然后,在渲染循环中(或者如果您对多线程+同步能力有信心,可以将它分成不同的循环),您可以编写如下代码:

float now = glfwGetTime();
static float last_update = now;
float delta_time = now - last_update;
last_update = now;
handle_input(delta_time);

handle_input看起来像这样:

float external_position[2];
std::map<int, std::function<void(/*args*/)>> key_functions;
void handle_input(float delta_time) {
    //Anything that should happen "when the users presses the key" should happen here
    while(!unhandled_keys.is_empty()) {
        key_event event = unhandled_keys.front();
        unhandled_keys.pop();
        key_functions[event.key](/*args*/);
        bool pressed = event.action == GLFW_PRESS || event.action == GLFW_REPEAT;
        keys[event.key] = pressed;
    }
    //Anything that should happen "while the key is held down" should happen here.
    float movement[2] = {0,0};
    if(keys[GLFW_KEY_W]) movement[0] += delta_time;
    if(keys[GLFW_KEY_S]) movement[0] -= delta_time;
    if(keys[GLFW_KEY_A]) movement[1] -= delta_time;
    if(keys[GLFW_KEY_D]) movement[1] += delta_time;
    external_position[0] += movement[0];
    external_position[1] += movement[1];
}

编辑:我已经添加逻辑来处理&#34;在媒体&#34; /&#34;发布&#34;类型功能。因此,例如,如果此代码位于渲染器中:

key_functions[GLFW_KEY_SPACE] = [&renderer] {renderer.pause();};

然后按[Space]键将暂停渲染器。

答案 1 :(得分:0)

好的,我会回答我自己的问题(让@Xirema的回答尽可能正确)

我想我只是理解为什么在重复帧率和回调之间没有同步,这是因为操作系统处理键重复的方式,它不会每秒发送4000+键重复信号(因为我得到4000+ fps) )并将自己限制在60个/ s左右! 为了解决这个问题,我确实只需在回调函数中注册最后一次按下的键60次/秒,并在每帧执行一次GLFWkeyfun(在主循环中)之外的函数,或者找到一种方法来规范化运动以避免口吃!

无论如何,再次感谢花时间回答@Xirema我希望我的问题对某人有用,现在,关闭代码真棒! (不是真的;-))

P.S:知道密钥重复信号的发送次数,使用key_repeat回调函数中固定的deltatime值也可以做到这一点!

PPS:嗯,考虑到键盘重复可能因操作系统或用户设置甚至CPU功率而异,最好的解决方案是为GLFWkeyfun设置单独的增量时间,这样您就可以将它发送到回调函数和总是得到正确的密钥重复增量时间,避免所有口吃!