OpenGL+ GLFW 按键处理(背景闪烁、按一次处理多次的问题)

  学习OpenGL的时候,https://learnopengl-cn.github.io/01 Getting started/03 Hello Window/, 说按键接受都用一个自己写的函数 void processInput(GLFWwindow *window) 来处理,但是实际尝试了一下,想在键盘 B 键按下的时候,随机刷新背景的颜色,使用 processInput 函数时,发现按键松开之后背景颜色还会闪烁,如下图(实际闪烁非常快,因为是gif,而且上传的gif不能太大的原因,所以闪烁频率很低)。
在这里插入图片描述

int main()
{
	srand(static_cast<int>(time(nullptr))); // for random number
	/*
	... 省略 ...
	*/
// Main loop - 渲染循环
	while (!glfwWindowShouldClose(window))
	{
		processInput(window); // 还是下边这个好用

		glfwPollEvents();
		glfwSwapBuffers(window);
	}
// Main loop - 渲染循环

	glfwDestroyWindow(window);
	glfwTerminate();
    return 0;
}

void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);

	// 接受键盘 B 键,随机修改背景颜色
	if(glfwGetKey(window, GLFW_KEY_B) == GLFW_PRESS)
	{
		background_r = rand() % 255 / 255.0;
		background_g = rand() % 255 / 255.0;
		background_b = rand() % 255 / 255.0;
		background_alpha = 1.0;
		printf("R: %.2lf, G: %.2lf, B: %.2lf, A: %.2lf\n", background_r, background_g, background_b, background_alpha);

		glClearColor(background_r, background_g, background_b, background_alpha);	// 状态设置函数
		glClear(GL_COLOR_BUFFER_BIT);	// 状态使用函数
	}
}

  可能是 glClearColor、glClear 两个状态函数不能放在这里,改为放在渲染的 main loop 里,R、G、B、A 四个参数改为全局变量,processInput 中只修改 R、G、B、A 的值。发现背景不会闪烁了,但是还是会出现,只按一下,但是背景修改多次(次数和按键时间长短有关),且输出语句输出多行。也就是说,在按键的这0.00几秒的时间内,渲染 main loop 循环跑了几次,就接收几次按键信息。只有按得非常非常快,才能只输出一次,背景变化一次,如下图。
在这里插入图片描述
  我当然是想按一次修改一次啊,所以就改成了 glfw 的回调函数 key_callback
  值得注意的是,回调函数的参数类型是不能自己修改的,ReSharper C++ 提示我参数应该是 const int& 类型,实际参数在函数中确实是不会变的,但是也不能改,否则会出错,因为需要和回调函数的设置一样。

// 参数类型不能变成 const int&,因为与回调函数设置不相符
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);

	// 接受键盘 B 键,随机修改背景颜色
	if (glfwGetKey(window, GLFW_KEY_B) == GLFW_PRESS)
	{
		background_r = rand() % 255 / 255.0;
		background_g = rand() % 255 / 255.0;
		background_b = rand() % 255 / 255.0;
		background_alpha = 1.0; // rand() % 255 / 255.0;
		printf("R: %.2lf, G: %.2lf, B: %.2lf, A: %.2lf\n", background_r, background_g, background_b, background_alpha);

		glClearColor(background_r, background_g, background_b, background_alpha);	// 状态设置函数
		glClear(GL_COLOR_BUFFER_BIT);	// 状态使用函数
	}
}

  改成这样之后,一次按键,确实只有一句输出,但是按键松开后,背景会闪烁,如下图。
在这里插入图片描述

  说明 背景闪烁的问题是,不能在渲染循环外修改 OpenGL 的 state,比如调用 glClear 函数。 把 glClear 放到 main loop 中,就可以解决这个问题,glClearColor 放在那里好像不影响结果,不过我还是把它和 glClear 放在了一起。

int main()
{
	srand(static_cast<int>(time(nullptr))); // for random number
	/*
	... 省略 ...
	*/
// Main loop - 渲染循环
	while (!glfwWindowShouldClose(window))
	{
		glfwSetKeyCallback(window, key_callback);

		glClearColor(background_r, background_g, background_b, background_alpha);	// 状态设置函数
		glClear(GL_COLOR_BUFFER_BIT);	// 状态使用函数
		
		glfwPollEvents();
		glfwSwapBuffers(window);
	}
// Main loop - 渲染循环

	glfwDestroyWindow(window);
	glfwTerminate();
    return 0;
}

// 参数类型不能变成 const int&,因为与回调函数设置不相符
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
	// 不要在这个函数中修改 OpenGL 的 state,比如调用 glClear 函数 !!!!!!!!

	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);

	// 接受键盘 B 键,随机修改背景颜色
	if (glfwGetKey(window, GLFW_KEY_B) == GLFW_PRESS)
	{
		background_r = rand() % 255 / 255.0;
		background_g = rand() % 255 / 255.0;
		background_b = rand() % 255 / 255.0;
		background_alpha = 1.0; // rand() % 255 / 255.0;
		printf("R: %.2lf, G: %.2lf, B: %.2lf, A: %.2lf\n", background_r, background_g, background_b, background_alpha);
	}
}

   key_callback 这样改了之后就对了,按一次刷新一次,输出一句,不过长按还是会不断刷新
在这里插入图片描述
  用 static 修饰的函数,限定在本源码文件中,不能被本源码文件以外的代码文件调用。而普通的函数,默认是 extern 的,也就是说它可以被其它代码文件调用。
  在函数的返回类型前加上关键字 static,将函数定义为静态函数有以下好处:
  <1> 其他文件中可以定义相同名字的函数,不会发生冲突。
  <2> 静态函数不能被其他文件所用。

猜你喜欢

转载自blog.csdn.net/Bob__yuan/article/details/87972189