鼠标输入

Posted keguniang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了鼠标输入相关的知识,希望对你有一定的参考价值。

一、隐藏并捕捉光标

偏航角和俯仰角是通过鼠标移动获得的,水平的移动影响偏航角,竖直的移动影响俯仰角。

原理是,存储上一帧鼠标的位置,在当前帧中计算鼠标位置与上一帧的位置相差多少。如果水平/竖直差别越大,那么俯仰角或偏航角就改变越大,也就是摄像机需要移动更多的距离。

首先我们应该告诉GLFW,它应该隐藏光标,并捕捉它。

结果:无论我们怎样移动鼠标,光标都不会显示,但它也不会离开窗口。

glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_DISABLED);

二:监听鼠标移动事件

为了计算俯仰角和偏航角,我们需要让GLFW监听鼠标移动事件(和键盘输入相似)。用一个回调函数来完成,函数原型如下:

void mouse_callback(GLFWwindow *window,double xpos,double ypos);

xpos,ypos代表当前鼠标的位置。当我们用GLFW注册了回调函数之后,鼠标一移动mouse_callback函数就会被调用:

1 glfwSetCursorCallback(window,mouse_callback);

三、在处理FPS风格摄像机的鼠标输入的时候,我们必须在最终获取方向向量之前做下面这几步

1、计算鼠标距上一帧的偏移量

2、把偏移量添加到摄像机的俯仰角和偏航角中

3、对俯仰角和偏航角进行最大和最小值的限制

4、计算方向向量

第一步:计算鼠标距上一帧的偏移量,所以必须在程序中存储上一帧的鼠标位置,我们把它的初始值设置为屏幕的中心

1 float lastX = screenWidth/2.0f;
2 float lastY = screenHeight/2.0f;

第二步:在鼠标的回调函数中计算当前帧和上一帧鼠标位置的偏移量:

1 float xoffest = xpos-lastX;
2 float yoffset = lastY - ypos;//注意这里是相反的,因为y坐标是从底部往顶部依次增大的
3 lastX = xpos;
4 lastY = ypos;
5 
6 float sensitivity = 0.05f;
7 xoffest *= sensitivity;
8 yoffest *= sensitivity;

注意我们把偏移量乘以了sensitivity(灵敏度)值。如果我们忽略这个值,鼠标移动就会太大了

俯仰角(Pitch)、偏航角(Yaw)

技术分享图片

接下来我们把偏移量加到全局变量pitch和yaw上

1 yaw +=xoffset;
2 pitch +=yoffset;

第三步:给摄像机添加一些限制,这样摄像机就不会发生奇怪的移动了。对于俯仰角,要让用户不能看高于89度的地方(在90度是视角会发生逆转,所以我们把89度看成极限),同样也不允许-89度。

1 if(pitch>89.0f)
2     pitch = 89.0f;
3 if(pitch <-89.0f)
4     pitch = -89.0f;

注意到我们没有给偏航角设置限制,这是因为我们不希望限制用户的水平旋转。

第四步:通过俯仰角和偏航角来计算得到真正的方向向量:

1 glm::vec3 front;
2 front.x = cos(glm::radians(pith))*cos(glm::radians(yaw));
3 front.y = sin(glm::radians(pitch));
4 front.z = cos(glm::radians(pith))*cos(glm::radians(yaw));
5 cameraFront = glm::normolize(front);

计算出来的方向向量就会包含根据鼠标移动计算出来所有的旋转了。

我们可以简单的使用一个bool变量检验我们是否是第一次获取鼠标输入,如果是,那么我们先把鼠标的初始位置更新为xposypos值,这样就能解决这个问题;接下来的鼠标移动就会使用刚进入的鼠标位置坐标来计算偏移量了:

1 if(firstMouse)//这个bool变量初始时是设定为true的
2 {
3     lastX = xpos;
4     lastY = ypos;
5     firstMouse = false;   
6 }

最后的代码应该是这样的:

 1 void mouse_callback(GLFWwindow* window, double xpos, double ypos)
 2 {
 3     if(firstMouse)
 4     {
 5         lastX = xpos;
 6         lastY = ypos;
 7         firstMouse = false;
 8     }
 9 
10     float xoffset = xpos - lastX;
11     float yoffset = lastY - ypos; 
12     lastX = xpos;
13     lastY = ypos;
14 
15     float sensitivity = 0.05;
16     xoffset *= sensitivity;
17     yoffset *= sensitivity;
18 
19     yaw   += xoffset;
20     pitch += yoffset;
21 
22     if(pitch > 89.0f)
23         pitch = 89.0f;
24     if(pitch < -89.0f)
25         pitch = -89.0f;
26 
27     glm::vec3 front;
28     front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
29     front.y = sin(glm::radians(pitch));
30     front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
31     cameraFront = glm::normalize(front);
32 }

三、缩放

实现一个缩放(Zoom)接口。在之前的教程中我们说视野(Field of View)或fov定义了我们可以看到场景中多大的范围。当视野变小时,场景投影出来的空间就会减小,产生放大(Zoom In)了的感觉。我们会使用鼠标的滚轮来放大。与鼠标移动、键盘输入一样,我们需要一个鼠标滚轮的回调函数:

1 void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
2 {
3   if(fov >= 1.0f && fov <= 45.0f)
4     fov -= yoffset;
5   if(fov <= 1.0f)
6     fov = 1.0f;
7   if(fov >= 45.0f)
8     fov = 45.0f;
9 }

当滚动鼠标滚轮的时候,yoffset值代表我们竖直滚动的大小。当scroll_callback函数被调用后,我们改变全局变量fov变量的内容。因为45.0f是默认的视野值,我们将会把缩放级别(Zoom Level)限制在1.0f45.0f

我们现在在每一帧都必须把透视投影矩阵上传到GPU,但现在使用fov变量作为它的视野:

projection = glm::perspective(glm::radians(fov), 800.0f / 600.0f, 0.1f, 100.0f);

最后不要忘记注册鼠标滚轮的回调函数:

glfwSetScrollCallback(window, scroll_callback);

 

以上是关于鼠标输入的主要内容,如果未能解决你的问题,请参考以下文章

JavaFX窗口拖动

Delphi7:快捷键

webstorm代码片段的创建

收藏|分享前端开发常用代码片段

片段(Java) | 机试题+算法思路+考点+代码解析 2023

如何使用sublime代码片段快速输入PHP头部版本声明