opengl鼠标键盘控制相机漫游
键盘wsad控制相机位移,鼠标左键按下控制相机旋转
效果如下
代码如下
#include <stdio.h> #include <string.h> #include <iostream> #include <fstream> #include <sstream> #include <GL/glew.h> #include <GL/freeglut.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> using namespace std; using namespace glm; const char* vsShaderName = "shader.vs";//顶点着色器 const char* fsShaderName = "shader.fs";//片元着色器 GLuint VBO;//顶点缓冲对象 GLuint IBO;//索引缓冲对象 static GLfloat *vertices;//顶点数组 static unsigned int *indices; //索引数组 GLuint ShaderProgram; GLuint MatrixID; int windowWidth = 800; int windowHeight = 800; //相机参数 glm::mat4 ViewMatrix;//视图矩阵 glm::mat4 ProjectionMatrix; //投影矩阵 glm::mat4 MVP;//模型视图矩阵 glm::mat4 ModelMatrix;//模型矩阵 glm::vec3 position = glm::vec3(5, 5, 5); //相机位置 float horizontalAngle = 3.14f; float verticalAngle = 0.0f; float initialFoV = 45.0f; //相机视场角 float speed = 0.05f; //平移速度 float mouseSpeed = 0.005f; int mouseX, mouseY;//鼠标位置 窗口坐标 bool mouseLeftDown=false;//鼠标左键按下 // 传递键盘事件 static void SpecialKeyboardCB(unsigned char Key, int x, int y) { glm::vec3 direction( cos(verticalAngle) * sin(horizontalAngle), sin(verticalAngle), cos(verticalAngle) * cos(horizontalAngle) ); glm::vec3 right = glm::vec3( sin(horizontalAngle - 3.14f / 2.0f), 0, cos(horizontalAngle - 3.14f / 2.0f) ); glm::vec3 up = glm::cross(right, direction); switch (Key) { case 'w': position += direction * speed; //fprintf(stderr, "up \n"); break; case 'd': position += right * speed; //fprintf(stderr, "right \n"); break; case 's': position -= direction * speed; //fprintf(stderr, "down \n"); break; case 'a': position -= right * speed; //fprintf(stderr, "left \n"); break; case 27: exit(1); break; default: break; //fprintf(stderr, "Unimplemented GLUT key\n"); //exit(1); } float FoV = initialFoV; ProjectionMatrix = glm::perspective(glm::radians(FoV), (float)windowWidth /(float) windowHeight, 0.1f, 100.0f); ViewMatrix = glm::lookAt( position, position + direction, up ); ModelMatrix = glm::mat4(1.0); MVP = ProjectionMatrix * ViewMatrix * ModelMatrix; glutPostRedisplay();//设置窗口重绘 } //传递鼠标事件 void mouseCB(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON) { if (state == GLUT_DOWN) { mouseLeftDown = true; mouseX = x; mouseY = y; } else if (state == GLUT_UP) { mouseLeftDown = false; } } } //传递鼠标位置 static void mouseMotionCB(int x, int y) { if (mouseLeftDown == true) { horizontalAngle += mouseSpeed * float(x - mouseX); verticalAngle += mouseSpeed * float(y - mouseY); mouseX = x; mouseY = y; SpecialKeyboardCB(0, 0, 0); } } //渲染回调函数 void RenderScenceCB() { // 清空颜色缓存 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_LINES, 0, 40*4); glDisableVertexAttribArray(0); //交换前后缓存 glutSwapBuffers(); } //创建顶点 static void CreateVertexBuffer() { vertices = new GLfloat[40*3]; for (size_t i = 0; i < 10; i++) { vertices[i * 12] = 0; vertices[i * 12 + 1] = 0; vertices[i * 12 + 2] = i; vertices[i * 12 + 3] = 9; vertices[i * 12 + 4] = 0; vertices[i * 12 + 5] = i; vertices[i * 12 + 6] = i; vertices[i * 12 + 7] = 0; vertices[i * 12 + 8] = 0; vertices[i * 12 + 9] = i; vertices[i * 12 + 10] = 0; vertices[i * 12 + 11] = 9; } glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, 40*3* sizeof(GLfloat), vertices, GL_STATIC_DRAW); } static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType) { // 根据shader类型参数定义两个shader对象 GLuint ShaderObj = glCreateShader(ShaderType); // 检查是否定义成功 if (ShaderObj == 0) { fprintf(stderr, "Error creating shader type %d\n", ShaderType); exit(0); } // 定义shader的代码源 const GLchar* p[1]; p[0] = pShaderText; GLint Lengths[1]; Lengths[0] = strlen(pShaderText); glShaderSource(ShaderObj, 1, p, Lengths); glCompileShader(ShaderObj);// 编译shader对象 // 检查和shader相关的错误 GLint success; glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success); if (!success) { GLchar InfoLog[1024]; glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog); fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog); exit(1); } // 将编译好的shader对象绑定到program object程序对象上 glAttachShader(ShaderProgram, ShaderObj); } // 编译着色器函数 static void CompileShaders() { // 创建着色器程序 ShaderProgram = glCreateProgram(); // 检查是否创建成功 if (ShaderProgram == 0) { fprintf(stderr, "Error creating shader program\n"); exit(1); } // 存储着色器文本的字符串 string vs, fs; // 分别读取着色器文件中的文本到字符串 std::ifstream VertexShaderStream(vsShaderName, std::ios::in); if (VertexShaderStream.is_open()) { std::stringstream sstr; sstr << VertexShaderStream.rdbuf(); vs = sstr.str(); VertexShaderStream.close(); } else { printf("Error to open %s\n", vsShaderName); getchar(); exit(0); } std::ifstream FragmentShaderStream(fsShaderName, std::ios::in); if (FragmentShaderStream.is_open()) { std::stringstream sstr; sstr << FragmentShaderStream.rdbuf(); fs = sstr.str(); FragmentShaderStream.close(); } // 添加顶点着色器和片段着色器 AddShader(ShaderProgram, vs.c_str(), GL_VERTEX_SHADER); AddShader(ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER); // 链接shader着色器程序,并检查程序相关错误 GLint Success = 0; GLchar ErrorLog[1024] = { 0 }; glLinkProgram(ShaderProgram); glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success); if (Success == 0) { glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog); exit(1); } // 检查验证在当前的管线状态程序是否可以被执行 glValidateProgram(ShaderProgram); glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success); if (!Success) { glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog); exit(1); } // 设置到管线声明中来使用上面成功建立的shader程序 glUseProgram(ShaderProgram); MatrixID = glGetUniformLocation(ShaderProgram, "gWVP"); } int main(int argc, char ** argv) { // 初始化GLUT glutInit(&argc, argv); // 显示模式:双缓冲、RGBA glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize(windowWidth, windowHeight); glutInitWindowPosition(100, 100); glutCreateWindow("CameraTest"); GLenum res = glewInit(); if (res != GLEW_OK) { fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res)); return 1; } // 开始渲染 glutDisplayFunc(RenderScenceCB); // 注册键盘事件 glutKeyboardFunc(SpecialKeyboardCB); //注册鼠标事件 glutMouseFunc(mouseCB); glutMotionFunc(mouseMotionCB); mouseX = windowWidth / 2; mouseY = windowHeight / 2; // 缓存清空后的颜色值 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); //创建顶点 CreateVertexBuffer(); // 编译着色器 CompileShaders(); //开启深度测试 glEnable(GL_DEPTH_TEST); // 通知开始GLUT的内部循环 glutMainLoop(); delete vertices; return 0; }
#version 330 layout (location = 0) in vec3 Position; uniform mat4 gWVP; out vec3 Color; void main() { gl_Position = gWVP * vec4(Position, 1.0); Color = Position/10; }
#version 330 out vec3 FragColor; in vec3 Color; void main() { FragColor = Color; }