OpenGL/GLFW/GLM - 键盘输入无响应

Posted

技术标签:

【中文标题】OpenGL/GLFW/GLM - 键盘输入无响应【英文标题】:OpenGL/GLFW/GLM - keyboard input unresponsive 【发布时间】:2017-06-26 09:41:27 【问题描述】:

我一直在关注this tutorial series,同时为我自己的目标定制代码(渲染 3D 点云)。我能够基于 mouse_input 回调来渲染和移动点云,并且可以使用滚动回调滚动进/出。根据我的阅读/理解,相机应该能够通过键盘输入围绕点云(模型)旋转。我正在使用 W、S、A、D 作为前、后、左、右输入。我试过小写和大写输入(不知道这是否有区别)。我似乎无法从模型中得到响应。

我已经检查了几次代码,真的看不出哪里出错了。

代码如下。

我正在使用 Visual Studio 2017 社区。​​p>

Source.cpp

#include <glad/glad.h>
#include <C:\\Users\\jhansen\\Desktop\\OpenGL\\glad\\KHR\\khrplatform.h>
#include <C:\\Users\\jhansen\\Desktop\\OpenGL\\glad\\glad.c>
#include <GLFW/glfw3.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <Shader.h>
#include <Camera.h>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow *window);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 800;

// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
bool firstMouse = true;


// timing
float deltaTime = 0.0f; // time between current frame and last frame
float lastFrame = 0.0f;


int main()

    // glfw: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X

    // glfw window creation
    // --------------------
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwSetCursorPosCallback(window, mouse_callback);
    glfwSetScrollCallback(window, scroll_callback);

    // tell GLFW to capture our mouse
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);

    // glad: load all OpenGL function pointers
    // ---------------------------------------
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    


    // configure global opengl state
    // -----------------------------
    glEnable(GL_DEPTH_TEST);

    Shader ourShader("VertexShader.vs",
        "FragShader.fs");



    // set up vertex data (and buffer(s)) and configure vertex attributes
    // ------------------------------------------------------------------
    float vertices[] = 
        -0.5f, -0.5f, 0.0f, // left  
        0.5f, -0.5f, 0.0f, // right 
        0.0f,  0.5f, 0.0f  // top   
    ;

    struct Point
    
        float x;
        float y;
        float z;
    ;

    Point points[32000];

    // Generate 32000 points
    for (int i = 0; i < 32000; i++)
    
        points[i].x = (float)((rand() % SCR_WIDTH) + 1);
        points[i].y = (float)((rand() % SCR_WIDTH) + 1);
        points[i].z = (float)((rand() % SCR_WIDTH) + 1);

        // X Coords to Normalised Device coordinates
        if (points[i].x > 400)
        
            points[i].x = points[i].x * 0.00125f;
        
        else if (points[i].x < 400)
        
            points[i].x = points[i].x * -0.00125f;
        
        else if (points[i].x == 400)
        
            points[i].x = 0.0f;
        

        // Y Coords to Normalised Device coordinates
        if (points[i].y > 400)
        
            points[i].y = points[i].y * 0.00125f;
        
        else if (points[i].y < 400)
        
            points[i].y = points[i].y * -0.00125f;
        
        else if (points[i].y == 400)
        
            points[i].y = 0.0f;
        

        // Z Coords to Normalised Device coordinates
        if (points[i].z > 400)
        
            points[i].z = points[i].z * 0.00125f;
        
        else if (points[i].z < 400)
        
            points[i].z = points[i].z * -0.00125f;
        
        else if (points[i].z == 400)
        
            points[i].z = 0.0f;
        

        //cout << points[i].x << ", " << points[i].y << ", " << points[i].z << endl;
    

    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0);


    // uncomment this call to draw in wireframe polygons.
    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    
        // input
        // -----
        processInput(window);

        // render
        // ------
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // activate shader
        ourShader.use();

        // pass projection matrix to shader (note that in this case it could change every frame)
        glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
        ourShader.setMat4("projection", projection);

        // camera/view transformation
        glm::mat4 view = camera.GetViewMatrix();
        ourShader.setMat4("view", view);

        glm::mat4 model;
        model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.3f, 0.5f));
        ourShader.setMat4("model", model);


        // draw our points array
        //glUseProgram(shaderProgram);
        glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
        glPointSize(3.0f);
        glDrawArrays(GL_POINTS, 0, 32000);
        // glBindVertexArray(0); // no need to unbind it every time 

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    

    // optional: de-allocate all resources once they've outlived their purpose:
    // ------------------------------------------------------------------------
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);

    // glfw: terminate, clearing all previously allocated GLFW resources.
    // ------------------------------------------------------------------
    glfwTerminate();
    return 0;


// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)

    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);

    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        camera.ProcessKeyboard(FORWARD, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        camera.ProcessKeyboard(BACKWARD, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        camera.ProcessKeyboard(LEFT, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        camera.ProcessKeyboard(RIGHT, deltaTime);


// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)

    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);



// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos)

    if (firstMouse)
    
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    

    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top

    lastX = xpos;
    lastY = ypos;

    camera.ProcessMouseMovement(xoffset, yoffset);


// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)

    camera.ProcessMouseScroll(yoffset);

Camera.h

#ifndef CAMERA_H
#define CAMERA_H

#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include <vector>

// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum Camera_Movement 
    FORWARD,
    BACKWARD,
    LEFT,
    RIGHT
;

// Default camera values
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVTY = 0.1f;
const float ZOOM = 45.0f;


// An abstract camera class that processes input and calculates the corresponding Eular Angles, Vectors and Matrices for use in OpenGL
class Camera

public:
    // Camera Attributes
    glm::vec3 Position;
    glm::vec3 Front;
    glm::vec3 Up;
    glm::vec3 Right;
    glm::vec3 WorldUp;
    // Eular Angles
    float Yaw;
    float Pitch;
    // Camera options
    float MovementSpeed;
    float MouseSensitivity;
    float Zoom;

    // Constructor with vectors
    Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM)
    
        Position = position;
        WorldUp = up;
        Yaw = yaw;
        Pitch = pitch;
        updateCameraVectors();
    
    // Constructor with scalar values
    Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM)
    
        Position = glm::vec3(posX, posY, posZ);
        WorldUp = glm::vec3(upX, upY, upZ);
        Yaw = yaw;
        Pitch = pitch;
        updateCameraVectors();
    

    // Returns the view matrix calculated using Eular Angles and the LookAt Matrix
    glm::mat4 GetViewMatrix()
    
        return glm::lookAt(Position, Position + Front, Up);
    

    // Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
    void ProcessKeyboard(Camera_Movement direction, float deltaTime)
    
        float velocity = MovementSpeed * deltaTime;
        if (direction == FORWARD)
            Position += Front * velocity;
        if (direction == BACKWARD)
            Position -= Front * velocity;
        if (direction == LEFT)
            Position -= Right * velocity;
        if (direction == RIGHT)
            Position += Right * velocity;
    

    // Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
    void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true)
    
        xoffset *= MouseSensitivity;
        yoffset *= MouseSensitivity;

        Yaw += xoffset;
        Pitch += yoffset;

        // Make sure that when pitch is out of bounds, screen doesn't get flipped
        if (constrainPitch)
        
            if (Pitch > 89.0f)
                Pitch = 89.0f;
            if (Pitch < -89.0f)
                Pitch = -89.0f;
        

        // Update Front, Right and Up Vectors using the updated Eular angles
        updateCameraVectors();
    

    // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
    void ProcessMouseScroll(float yoffset)
    
        if (Zoom >= 1.0f && Zoom <= 45.0f)
            Zoom -= yoffset;
        if (Zoom <= 1.0f)
            Zoom = 1.0f;
        if (Zoom >= 45.0f)
            Zoom = 45.0f;
    

private:
    // Calculates the front vector from the Camera's (updated) Eular Angles
    void updateCameraVectors()
    
        // Calculate the new Front vector
        glm::vec3 front;
        front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
        front.y = sin(glm::radians(Pitch));
        front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
        Front = glm::normalize(front);
        // Also re-calculate the Right and Up vector
        Right = glm::normalize(glm::cross(Front, WorldUp));  // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
        Up = glm::normalize(glm::cross(Right, Front));
    
;
#endif

【问题讨论】:

【参考方案1】:

这可能会对您有所帮助,因为这是我的 Player::move() 方法中的一个很好的参考,其中不同的动作是枚举类型。

// -----------------------------------------------------------------------
// move()
// Move The Player In A Desired Direction
void Player::move( Action action, float fDeltaTime ) 

    Vector3 v3LookDirection;
    v3LookDirection = m_v3LookCenter - m_v3Position;

    switch ( action ) 
        case MOVING_FORWARD: 
            // Prevent Vertical Motion
            v3LookDirection.m_fY = 0.0f;
            m_v3Position   += v3LookDirection * fDeltaTime * m_fLinearSpeed;
            m_v3LookCenter += v3LookDirection * fDeltaTime * m_fLinearSpeed;
            break;
        
        case MOVING_BACK: 
            // Prevent Vertical Motion
            v3LookDirection.m_fY = 0.0f;
            m_v3Position   -= v3LookDirection * fDeltaTime * m_fLinearSpeed;
            m_v3LookCenter -= v3LookDirection * fDeltaTime * m_fLinearSpeed;
            break;
        
        case MOVING_LEFT: 
            // Get "Side" Direction & Prevent Vertical Motion
            v3LookDirection.m_fY =  v3LookDirection.m_fX;
            v3LookDirection.m_fX = -v3LookDirection.m_fZ;
            v3LookDirection.m_fZ =  v3LookDirection.m_fY;
            v3LookDirection.m_fY =  0.0f;

            m_v3Position   -= v3LookDirection * fDeltaTime * m_fLinearSpeed;
            m_v3LookCenter -= v3LookDirection * fDeltaTime * m_fLinearSpeed;
            break;
        
        case MOVING_RIGHT: 
            // Get "Side" Direction & Prevent Vertical Motion
            v3LookDirection.m_fY =  v3LookDirection.m_fX;
            v3LookDirection.m_fX = -v3LookDirection.m_fZ;
            v3LookDirection.m_fZ =  v3LookDirection.m_fY;
            v3LookDirection.m_fY =  0.0f;

            m_v3Position   += v3LookDirection * fDeltaTime * m_fLinearSpeed;
            m_v3LookCenter += v3LookDirection * fDeltaTime * m_fLinearSpeed;
            break;
        
        case LOOKING_LEFT: 

            /*float fSin = -sin( fDeltaTime * m_fAngularSpeed );
            float fCos =  cos( fDeltaTime * m_fAngularSpeed );

            m_v3LookCenter.m_fX = m_v3Position.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
            m_v3LookCenter.m_fZ = m_v3Position.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
            break;*/

            // Third Person
            float fSin = sin( fDeltaTime * m_fAngularSpeed );
            float fCos = -cos( fDeltaTime * m_fAngularSpeed );

            m_v3Position.m_fX = m_v3LookCenter.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
            m_v3Position.m_fZ = m_v3LookCenter.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
            break;
        
        case LOOKING_RIGHT: 
            /*float fSin = sin( fDeltaTime * m_fAngularSpeed );
            float fCos = cos( fDeltaTime * m_fAngularSpeed );

            m_v3LookCenter.m_fX = m_v3Position.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
            m_v3LookCenter.m_fZ = m_v3Position.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
            break;*/

            // Third Person
            float fSin = -sin( fDeltaTime * _fAngularSpeed );
            float fCos = -cos( fDeltaTime * _fAngularSpeed );

            m_v3Position.m_fX = m_v3LookCenter.m_fX + (-fSin * v3LookDirection.m_fZ + fCos * v3LookDirection.m_fX );
            m_v3Position.m_fZ = m_v3LookCenter.m_fZ + ( fCos * v3LookDirection.m_fZ + fSin * v3LookDirection.m_fX );
            break;
        
        case LOOKING_UP: 
            m_v3LookCenter.m_fY -= fDeltaTime * m_fAngularSpeed * m_MouseLookState;

            // Check Maximum Values
            if ( m_v3LookCenter.m_fY > (m_v3Position.m_fY + m_fMaxUp ) ) 
                m_v3LookCenter.m_fY = m_v3Position.m_fY + m_fMaxUp;
             else if ( m_v3LookCenter.m_fY < (m_v3Position.m_fY - m_fMaxDown) ) 
                m_v3LookCenter.m_fY = m_v3Position.m_fY - _fMaxDown;
            
            break;
        
    

 // move

这是我学习 OpenGL 1.0(旧版)时的一个旧项目。一切都是手动完成的,没有现有的库;甚至不得不写几个向量库。这个播放器类独立于Camera 类,但从中获取它的位置和查看方向向量。它们紧密集成到一个 GameOGL 类中,该类创建一个窗口、消息进程、消息处理程序并设置所有 OpenGL 的东西以及一个非常大的场景类对象。这里使用的数学是因为它属于一个 3D 游戏引擎,其中制作了第三人称视角地牢类型的游戏。只需确保您使用适当的旋转矩阵和三角方法来根据您的 3D 图形系统的手性进行旋转。

您尝试实现的旋转运动也可能不同。这会导致播放器 - 相机左右转动,就好像您在看远方一样。您可能想要的旋转类型几乎被认为与您的观看方向和距离保持固定在模型上但您的相机以特定旋转速度在世界中旋转的方式相反。

【讨论】:

以上是关于OpenGL/GLFW/GLM - 键盘输入无响应的主要内容,如果未能解决你的问题,请参考以下文章

联想笔记本更新biso后键盘无响应

text 从华为P9软键盘删除时无响应到InputConnectionWrapper

解决SSH自动断线,无响应的问题。

ubuntu文本编辑器无响应

Android 输入法没有传递键盘DELETE事件

C++非阻塞键盘缓冲区输入检测或读取函数是啥?