• 鼠标输入


    一、隐藏并捕捉光标

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

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

    首先我们应该告诉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);
  • 相关阅读:
    Lua手册中的string.len 不解
    计算机词汇(Computer Glossary)
    Qt 信号和槽机制的优缺点
    多线程,什么时候该使用?
    Linux进行挂起和杀死挂起进程
    struct和class的区别
    Number of 1 Bits
    Pascal's Triangle
    Excel Sheet Column Title
    c++单向链表
  • 原文地址:https://www.cnblogs.com/keguniang/p/9949855.html
Copyright © 2020-2023  润新知