Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C GLFW密钥回调同步_C_Opengl_3d_Glfw - Fatal编程技术网

C GLFW密钥回调同步

C GLFW密钥回调同步,c,opengl,3d,glfw,C,Opengl,3d,Glfw,一般来说,我对GLFW和OpenGL比较陌生,我正在开发一个小型模型渲染器。 我目前正在处理输入,我面临GLFW如何处理输入的问题,让我解释一下: 每个教程都告诉我们使用glfwGetKey和“if-forest”来查看是否按下了某某键。我遇到的问题是,如果我映射了很多关键点,它可能会变得很慢,而且很难看。 所以我使用函数指针表和glfwSetKeyCallback来加速这一过程并获得更清晰的代码。 我遇到的问题是,我正面临着一个看起来像是比赛的环境,相机似乎结巴了。 为了保持恒定的速度,我在每

一般来说,我对GLFW和OpenGL比较陌生,我正在开发一个小型模型渲染器。 我目前正在处理输入,我面临GLFW如何处理输入的问题,让我解释一下: 每个教程都告诉我们使用glfwGetKey和“if-forest”来查看是否按下了某某键。我遇到的问题是,如果我映射了很多关键点,它可能会变得很慢,而且很难看。 所以我使用函数指针表和glfwSetKeyCallback来加速这一过程并获得更清晰的代码。 我遇到的问题是,我正面临着一个看起来像是比赛的环境,相机似乎结巴了。 为了保持恒定的速度,我在每一帧上计算一个增量时间。 从我所看到的,似乎每隔一段时间调用一次键回调函数,而不是在重复键时在每帧调用一次。。。 我使用的是来自github的最新版本的glfw3,我在每个循环开始时交换缓冲区,在循环结束时使用glfwPollEvents()

我的问题是:是否有一种方法可以同步glfwPollEvents调用和渲染,以避免渲染循环和回调函数之间的口吃和deltatime差异?
提前感谢您的帮助

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

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());
}
其中
handle\u input
如下所示:

float now = glfwGetTime();
static float last_update = now;
float delta_time = now - last_update;
last_update = now;
handle_input(delta_time);
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];
}

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

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

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());
}
其中
handle\u input
如下所示:

float now = glfwGetTime();
static float last_update = now;
float delta_time = now - last_update;
last_update = now;
handle_input(delta_time);
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];
}

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

好的,我将回答我自己的问题(并让@Xirema的答案保持正确)

我想我刚刚理解了为什么它不能在帧速率和重复时回调之间同步,这是因为操作系统处理按键重复的方式,它不会每秒发送4000多个按键重复信号(因为我获得了4000多个fps),并且将自身限制在60次呼叫/秒左右! 为了纠正这个问题,我只需在回调函数中以60次/s的速度注册最后一次按下的键,并在GLFWkeyfun(主循环中)之外每帧执行一次该函数,或者找到一种方法使动作正常化以避免口吃

无论如何,再次感谢您抽出时间回答@Xirema我希望我的问题对某人有用,现在,开始编写精彩的代码吧!(不是真的;-))

注意:知道重复键信号被发送了多少次,在重复键回调函数中使用一个固定的deltatime值也可以做到这一点


p.p.S:嗯,考虑到键盘重复可能会因操作系统或用户设置甚至CPU功率的不同而有所不同,最好的解决方案是为GLFWkeyfun设置一个单独的增量时间,这样您就可以将它发送到回调函数,并始终获得正确的增量时间来重复按键,避免所有的口吃

好吧,那么,我来回答我自己的问题(并让@Xirema的回答像他说的那样有效)

我想我刚刚理解了为什么它不能在帧速率和重复时回调之间同步,这是因为操作系统处理按键重复的方式,它不会每秒发送4000多个按键重复信号(因为我获得了4000多个fps),并且将自身限制在60次呼叫/秒左右! 为了纠正这个问题,我只需在回调函数中以60次/s的速度注册最后一次按下的键,并在GLFWkeyfun(主循环中)之外每帧执行一次该函数,或者找到一种方法使动作正常化以避免口吃

无论如何,再次感谢您抽出时间回答@Xirema我希望我的问题对某人有用,现在,开始编写精彩的代码吧!(不是真的;-))

注意:知道重复键信号被发送了多少次,在重复键回调函数中使用一个固定的deltatime值也可以做到这一点


p.p.S:嗯,考虑到键盘重复可能会因操作系统或用户设置甚至CPU功率的不同而有所不同,最好的解决方案是为GLFWkeyfun设置一个单独的增量时间,这样您就可以将它发送到回调函数,并始终获得正确的增量时间来重复按键,避免所有的口吃

你好,非常感谢你的回答!这段代码的问题是有一个我称之为“if-forest”的东西,意思是它会检查每个键一次。。。我所寻找的是一种知道按下哪个键并获取键码的方法(glfwSetKeyCallback允许您这样做),这样我就可以调用我的键的回调函数,比如:key[keycode][action].function(keycode,action,mods,key[keycode][action].arg);这是一个更快更干净的我。。。问题是,当使用glfwSetKeyCallback时,我会遇到同步问题…@Tab我想说的是,回调应该是非常轻量级的。让回调函数执行可能需要几微秒以上的任务是不好的。我将添加一些代码来专门处理“按下时”类型的逻辑。@Tab我已经用一些额外的信息更新了帖子。非常感谢您的回答,我想我暂时不使用glfwSetKeyCallback(因为它运行60次/s,无论什么情况),并尝试寻找替代解决方案,可能使用其他库(SDL看起来不错,虽然有点“侵入性”)顺便说一句,在强制ActiveSync时,同步问题似乎不那么严重,但我现在想保持尽可能高的帧速率(事实上主要是为了好玩),并且可以选择以后是否限制帧速率谢谢您的时间,接受了答案!;)你好,非常感谢你的回答!这段代码的问题是有一个我称之为“if-forest”的东西,意思是它会检查每个键一次。。。我要寻找的是一种知道按下哪个键并获取键代码的方法(glfwSetKeyCallback允许您这样做),这样我就可以调用我的