接上一章:OpenGL基础14:摄像机 现在来尝试通过输入控制摄像机 其实从第一章开始,代码里面一直都有实现键盘输入: 实现的是:按下Esc键,关闭窗口 这样的话,如果我们想通过WASD来控制摄像机往对应方向移动,就只需要多加几行判定: 还记得上一章的LookAt方法嘛,里面传入的是摄像机位置、目标位置和世界空间的上向量,其中摄像机位置对应的正是cameraPos,而世界空间的上向量对应的是cameraUp,我们设定cameraFront为摄像机的方向向量,那么目标位置就可以是cameraPos + cameraFront 初始化全局变量: LookAt方法传参: 经过测试你会发现两个问题: 原因是keyCallback每次只能同时响应一个key,因此正确的方法是在 while (!glfwWindowShouldClose(window)) 循环内判断哪些按键是按下状态,并进行值的更新,这样的话,keyCallback回调里面我们只需要记录和改变按键的状态就可以了,改动如下: 测试一下,非常舒服! 一般电脑游戏流畅运行,大概是1秒60帧左右,也就是FPS = 60,如果配置强悍,FPS能到达144以上,每台电脑每秒绘制的次数不同就会导致在同样的时间内,上面的cameraMove()方法调用的次数不同 当我们发布我们的游戏/应用时,我们需要确保无论哪台设备,输入控制的移动速度都一样,可是上面的代码是做不到这一点的,这个时候我们就需要deltaTime这个变量,如果之前学过Unity3D等其它图形应用的话,应该都会对这个变量非常清楚,它储存着渲染上一帧所用的时间 这样的话,我们只需要每一帧进行cameraMove()计算的时候,将 openGL的话,自己算吧: 有了键盘输入后,我们来看看鼠标的输入 一般游戏都有滑动滚轮控制视角缩放的功能,这里也尝试一下: 和键盘输入一样:注册回调函数并实现 修改下投影矩阵,搞定! 上面实现了摄像机的移动和缩放,当然还有一个非常重要的东西:摄像机视角控制 一般游戏的视角都是通过鼠标的移动来控制的,这相对于移动和缩放,要更难和复杂,所以这一章就先不讲了 现在暂时只了解如何获取鼠标的移动事件以及按键点击事件吧 鼠标点击事件: 鼠标移动事件: 别忘了窗口y轴坐标是从下往上的!所以从代码中可以看到:在计算y轴的移动差的时候,是反过来的 隐藏光标: 完整代码: 一、键盘输入
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); }
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); GLfloat cameraSpeed = 0.05f; if (key == GLFW_KEY_W) cameraPos += cameraSpeed * cameraFront; if (key == GLFW_KEY_S) cameraPos -= cameraSpeed * cameraFront; if (key == GLFW_KEY_A) cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; if (key == GLFW_KEY_D) cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; }
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
void cameraMove() { GLfloat cameraSpeed = 0.05f; if (keys[GLFW_KEY_W]) cameraPos += cameraSpeed * cameraFront; if (keys[GLFW_KEY_S]) cameraPos -= cameraSpeed * cameraFront; if (keys[GLFW_KEY_A]) cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; if (keys[GLFW_KEY_D]) cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; } void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); if (action == GLFW_PRESS) //如果当前是按下操作 keys[key] = true; else if (action == GLFW_RELEASE) //松开键盘 keys[key] = false; }
while (!glfwWindowShouldClose(window)) { //…… cameraMove(); //…… }
二、
deltaTime
变量deltaTime
的值乘以速度参数,这样就可以做到速度与刷新率的平衡,无论你的机器快还是慢,摄像机的速度都会保持一致,每个用户的体验就都一样了
GLfloat deltaTime = 0.0f; GLfloat lastFrame = 0.0f; void cameraMove() { GLfloat currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; GLfloat cameraSpeed = 1.0f * deltaTime; if (keys[GLFW_KEY_W]) cameraPos += cameraSpeed * cameraFront; if (keys[GLFW_KEY_S]) cameraPos -= cameraSpeed * cameraFront; if (keys[GLFW_KEY_A]) cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; if (keys[GLFW_KEY_D]) cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; }
三、滚轮缩放
glfwSetScrollCallback(window, scroll_callback);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { if (aspect >= 1.0f && aspect <= 45.0f) aspect -= yoffset; if (aspect <= 1.0f) aspect = 1.0f; if (aspect >= 45.0f) aspect = 45.0f; }
projection = glm::perspective(glm::radians(aspect), (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f);
四、其它鼠标输入
glfwSetMouseButtonCallback(window, mouse_button_callback);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { if (action == GLFW_PRESS) { switch (button) { case GLFW_MOUSE_BUTTON_LEFT: printf("鼠标左键按下!!"); break; case GLFW_MOUSE_BUTTON_MIDDLE: printf("鼠标中间按下!!"); break; case GLFW_MOUSE_BUTTON_RIGHT: printf("鼠标右键按下!!"); break; default: return; } } return; }
glfwSetCursorPosCallback(window, mouse_callback);
void mouse_callback(GLFWwindow* window, double xpos, double ypos) { if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; } GLfloat xoffset = xpos - lastX; GLfloat yoffset = lastY - ypos; lastX = xpos; lastY = ypos; printf("鼠标移动差:x = %.1f, y = %.1f", xoffset, yoffset); }
#include<iostream> #include<opengl/glew.h> #define GLEW_STATIC #include<GLFW/glfw3.h> #include<glm/glm.hpp> #include<glm/gtc/matrix_transform.hpp> #include<glm/gtc/type_ptr.hpp> #include"Shader.h" #include<opengl/freeglut.h> #include<SOIL.h> bool keys[1024]; bool firstMouse = true; GLfloat lastX, lastY; void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void mouse_button_callback(GLFWwindow* window, int button, int action, int mods); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void cameraMove(); GLfloat aspect = 45.0f; const GLuint WIDTH = 800, HEIGHT = 600; glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr); glfwMakeContextCurrent(window); glfwSetKeyCallback(window, key_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); glfwSetMouseButtonCallback(window, mouse_button_callback); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glewExperimental = GL_TRUE; glewInit(); int width, height; glfwGetFramebufferSize(window, &width, &height); glViewport(0, 0, width, height); Shader shaderYellow("VShader.txt", "FShaderY.txt"); GLfloat vertices[] = { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, -0.5f, 0.5f, -0.5f, 0.0f, 1.0f }; GLuint VBO, VAO, texture; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenTextures(1, &texture); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBindTexture(GL_TEXTURE_2D, texture); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); int picWidth, picHeight; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); unsigned char* image = SOIL_load_image("Texture/wood.jpg", &picWidth, &picHeight, 0, SOIL_LOAD_RGB); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, picWidth, picHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); SOIL_free_image_data(image); glBindTexture(GL_TEXTURE_2D, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); glEnable(GL_DEPTH_TEST); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT); cameraMove(); glBindTexture(GL_TEXTURE_2D, texture); shaderYellow.Use(); float radius = 5.0f; float camX = sin(glfwGetTime()) * radius; float camZ = cos(glfwGetTime()) * radius; glm::mat4 model = glm::mat4(1.0f); glm::mat4 view = glm::mat4(1.0f); glm::mat4 projection = glm::mat4(1.0f); model = glm::rotate(model, glm::radians(57.0f), glm::vec3(-0.5f, 1.0f, 0.0f)); view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); projection = glm::perspective(glm::radians(aspect), (GLfloat)WIDTH / (GLfloat)HEIGHT, 0.1f, 100.0f); GLint modelLoc = glGetUniformLocation(shaderYellow.Program, "model"); GLint viewLoc = glGetUniformLocation(shaderYellow.Program, "view"); GLint projLoc = glGetUniformLocation(shaderYellow.Program, "projection"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection)); glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); glfwSwapBuffers(window); } glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glfwTerminate(); return 0; } GLfloat deltaTime = 0.0f; GLfloat lastFrame = 0.0f; void cameraMove() { GLfloat currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; GLfloat cameraSpeed = 1.0f * deltaTime; if (keys[GLFW_KEY_W]) cameraPos += cameraSpeed * cameraFront; if (keys[GLFW_KEY_S]) cameraPos -= cameraSpeed * cameraFront; if (keys[GLFW_KEY_A]) cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; if (keys[GLFW_KEY_D]) cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed; } void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); if (action == GLFW_PRESS) //如果当前是按下操作 keys[key] = true; else if (action == GLFW_RELEASE) //松开键盘 keys[key] = false; } void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { if (aspect >= 1.0f && aspect <= 45.0f) aspect -= yoffset; if (aspect <= 1.0f) aspect = 1.0f; if (aspect >= 45.0f) aspect = 45.0f; } void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { if (action == GLFW_PRESS) { switch (button) { case GLFW_MOUSE_BUTTON_LEFT: printf("鼠标左键按下!!"); break; case GLFW_MOUSE_BUTTON_MIDDLE: printf("鼠标中间按下!!"); break; case GLFW_MOUSE_BUTTON_RIGHT: printf("鼠标右键按下!!"); break; default: return; } } return; } void mouse_callback(GLFWwindow* window, double xpos, double ypos) { if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; } GLfloat xoffset = xpos - lastX; GLfloat yoffset = lastY - ypos; lastX = xpos; lastY = ypos; printf("鼠标移动差:x = %.1f, y = %.1f", xoffset, yoffset); }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算