当前位置: 首页 > 知识库问答 >
问题:

GLFW键回调同步

幸鸿轩
2023-03-14

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

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

共有2个答案

汪修诚
2023-03-14

好吧,那么,我将回答我自己的问题(并保留@xirema的答案,因为他是正确的)

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

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

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

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

司徒良哲
2023-03-14

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

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];
}

编辑:我添加了逻辑来处理“按下”/“释放”类型的函数。例如,如果此代码在渲染器中:

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

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

 类似资料:
  • 在中设置回调函数时,要使用什么? 我尝试将函数设置为类型<code>void。将其更改为<code>void __stdcall,但如何使用<code>GLFW的<code>typedef,例如<code>GLFW*fun?我认为这是正确的选择。我真的需要一个示例源代码。 顺便说一句,我将GLFW定义为 更新 我的代码是这样的: (我以三种方式做到了) 一 原型。因为在下面,所以这个给我一个编译错

  • 我目前正在使用OpenGL和GLFW开发一个跨平台的2D渲染引擎。我有一个名为GameWindow的基本窗口类,以及一个名为Game的继承GameWindow的类。游戏覆盖了基类中的一些虚拟方法,以便GameWindow可以处理帧限制等。在GameWindow的构造函数中,我使用glfwSetWindowSizeCallback指定窗口调整大小时要运行的方法。然后,此方法调用GameWindow的

  • 我目前正在创建一个轻量级的程序来查看和操作类似于程序Blender或3DS max的3D对象。 我正在使用C、GLFW和OpenGL。虽然我计划让它跨平台,但我目前只在一台运行Debian9.0(stretch)和XFCE桌面环境的计算机上工作。 目前回调glfwSetDropCallback似乎从来没有被调用,无论我尝试什么。我已经设定了断点和断言,但什么都没有。我尝试过的所有其他回调都很好。我

  • 当我按下一个键时,我试图让我的游戏做些什么。我正在使用GLFW为我处理Windows API。当我在标题中使用提及回调函数时,我陷入了困境和困惑。 参考文件:https://www.glfw.org/docs/latest/input_guide.html#input_keyboard 我遵循了“键输入”资源(不是“文本输入”),但我得到了一种文本输入回调曲线,比如,当我一直按下一个键时,我得到了

  • GLFW是一个OpenGL的应用框架,支持Linux和Windows。GLFW 主要用来处理特定操作系统下的特定任务,例如 OpenGL 窗口管理、分辨率切换、键盘、鼠标以及游戏手柄、定时器输入、线程创建等等。 更多的效果截图:http://glfw.sourceforge.net/screenshots.html