本文的代码是 LearnOpenGL 中对应代码,这里提供学习,大家喜欢的可去官方网站去看看:
LearnOpenGL-CNhttps://learnopengl-cn.readthedocs.io/zh/latest/
本章讲解摄像机的移动。
欧拉角是表示3D空间中可以表示任何旋转的三个值, 由莱昂哈德·欧拉在18世纪提出。 有三种
欧拉角: 俯仰角(Pitch)、 偏航角(Yaw)和滚转角(Roll), 下面的图片展示了它们的含义:

下面看看添加鼠标,键盘,视角的变化吧。

顶点着色器:
- #version 330 core
- layout (location = 0) in vec3 aPos;
- layout (location = 1) in vec2 aTexCoord;
-
- out vec2 TexCoord;
- uniform mat4 model;
- uniform mat4 view;
- uniform mat4 projection;
- void main()
- {
- gl_Position =projection*view*model* vec4(aPos, 1.0);
- TexCoord = vec2(aTexCoord.x, aTexCoord.y);
- }
片段着色器:
- #version 330 core
- out vec4 FragColor;
-
- in vec2 TexCoord;
-
- // texture samplers
- uniform sampler2D texture1;
- uniform sampler2D texture2;
-
- void main()
- {
- // linearly interpolate between both textures (80% container, 20% awesomeface)
- FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
- //FragColor =texture(texture2,TexCoord);
- }
源码部分:
- #ifndef BKQOPENGLW_H
- #define BKQOPENGLW_H
-
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- class BKQOpenglW : public QOpenGLWidget, QOpenGLFunctions_3_3_Core
- {
- Q_OBJECT
- public:
- enum Shape{None,Rect,circle,Triangle};
- explicit BKQOpenglW(QWidget *parent = nullptr);
- ~BKQOpenglW();
- void drawShapes(Shape shape);
- void setWireFrame(bool b);
- protected:
- //设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
- virtual void initializeGL() override;
- //渲染OpenGL场景,每当需要更新小部件时使用
- virtual void resizeGL(int w, int h) override;
- //设置OpenGL视口、投影等,每当尺寸大小改变时调用
- virtual void paintGL() override;
- //键盘操作重载Qt的事件处理
- virtual void keyPressEvent(QKeyEvent *event) override;
- //鼠标操作,重载Qt的事件处理
- void mousePressEvent(QMouseEvent *event) override;
- void mouseReleaseEvent(QMouseEvent *event) override;
- void mouseMoveEvent(QMouseEvent *event) override;
- void wheelEvent(QWheelEvent *event) override;
- private:
- //计算
- void calculateCamera();
- QMatrix4x4 getViewMatrix();
- signals:
-
- public slots:
-
- private:
- unsigned int VBO, VAO,EBO;
- Shape m_Shape;
- QOpenGLShaderProgram shaderProgram;
- unsigned int texture;
- QOpenGLTexture *pTexture;
- QOpenGLTexture *pTexture2;
-
- QTimer timer;
- int rotate{ 0 };
-
- //鼠标位置
- QPoint mousePos;
- QVector3D cameraPos{ 0.0f, 0.0f, 3.0f };
- QVector3D cameraFront{ 0.0f, 0.0f, -1.0f };
- QVector3D cameraUp{ 0.0f, 1.0f, 0.0f };
- QVector3D cameraRight{ 1.0f, 0.0f, 0.0f };
- //Euler Angles
- //偏航角如果是0.0f,指向的是 x轴正方向,即右方向,所以向里转90度,初始方向指向z轴负方向
- float eulerYaw{ -90.0f }; //偏航角,绕y左右转
- float eulerPitch{ 0.0f }; //俯仰角,绕x上下转
- //Camera options
- float cameraSpeed{ 0.5f }; //移动速度
- float cameraSensitivity{ 0.1f }; //鼠标拖动灵敏度
- float projectionFovy{ 45.0f }; //透视投影的fovy参数,视野范围
-
-
- };
-
- #endif // BKQOPENGLW_H
对应cpp
- #include "bkqopenglw.h"
- #include
- #include
- #include
- #include
- #include
- #define STB_IMAGE_IMPLEMENTATION
- #include "stb_image.h"
-
- #if 0
- float vertices[] = {
- // positions // colors // texture coords
- 0.8f, 0.8f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, // top right
- 0.8f, -0.8f, 0.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, // bottom right
- -0.8f, -0.8f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
- -0.8f, 0.8f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 2.0f // top left
- };
-
- #endif
-
- //顶点数据(盒子六个面,一个面两个三角)
- float 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
- };
-
-
- unsigned int indices[] = { // note that we start from 0!
- 0, 1, 3, // first Triangle
- 1, 2, 3 // second Triangle
- };
-
-
- //绘制多个盒子
- static QVector3D cubePositions[] = {
- QVector3D( 0.0f, 0.0f, 0.0f),
- QVector3D( 2.0f, 5.0f, -15.0f),
- QVector3D(-1.5f, -2.2f, -2.5f),
- QVector3D(-3.8f, -2.0f, -12.3f),
- QVector3D( 2.4f, -0.4f, -3.5f),
- QVector3D(-1.7f, 3.0f, -7.5f),
- QVector3D( 1.3f, -2.0f, -2.5f),
- QVector3D( 1.5f, 2.0f, -2.5f),
- QVector3D( 1.5f, 0.2f, -1.5f),
- QVector3D(-1.3f, 1.0f, -1.5f)
- };
-
-
- BKQOpenglW::BKQOpenglW(QWidget *parent) : QOpenGLWidget(parent)
- {
- setFocusPolicy(Qt::StrongFocus);
- // QSurfaceFormat fmt = format();
- // fmt.setRenderableType(QSurfaceFormat::OpenGL);
- // fmt.setProfile(QSurfaceFormat::CoreProfile);
- fmt.setVersion(3, 3);
- // //当启用多重采样时,将每个像素的首选样本数设置为numSamples
- // fmt.setSamples(4);
- // setFormat(fmt);
-
-
- connect(&timer,&QTimer::timeout,this,[this](){
- rotate+=2;
- if(isVisible()){
- update();
- }
- });
- timer.setInterval(50);
- //弧度转换
- calculateCamera();
-
- }
-
- BKQOpenglW::~BKQOpenglW()
- {
- makeCurrent();
- glDeleteVertexArrays(1,&VAO);
- glDeleteBuffers(1,&VBO);
- doneCurrent();
- }
-
- void BKQOpenglW::drawShapes(BKQOpenglW::Shape shape)
- {
- m_Shape = shape;
- update();
- }
-
- void BKQOpenglW::setWireFrame(bool b)
- {
- makeCurrent();
- if(b)
- {
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- }
- else {
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- }
- update();
- doneCurrent();
- }
-
- void BKQOpenglW::initializeGL()
- {
- initializeOpenGLFunctions();
-
- // shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,vertexShaderSource);
- // shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,fragmentShaderSource);
- shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/shader.vs");
- shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/shader.fs");
- shaderProgram.link();
- 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(vertices), vertices, GL_STATIC_DRAW);
-
- //绑定ebo
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
-
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
- glEnableVertexAttribArray(0);
-
- // texture coord attribute
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
- glEnableVertexAttribArray(1);
-
- //绑定纹理
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
- pTexture = new QOpenGLTexture(QImage(":/images/images/brickwall.jpg").mirrored());
- pTexture2 = new QOpenGLTexture(QImage(":/images/images/awesomeface.png").mirrored());
- shaderProgram.bind();
- shaderProgram.setUniformValue("texture1",0);
- shaderProgram.setUniformValue("texture2",1);
- //默认为GL_REPEAT 重复 GL_MIRRORED_REPEAT镜像 GL_CLAMP_TO_EDGE 边缘拉伸 GL_CLAMP_TO_BORDER 超出部分使用用户定义
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT); // we want to repeat the awesomeface pattern so we kept it at GL_REPEAT
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT);
-
-
- QMatrix4x4 projection; //透视投影
- //坐标到达观察空间之后,我们需要将其投影到裁剪坐标。
- //裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上
- //参数1:指定视景体的视野的角度
- //参数2:指定你的视景体的宽高比
- //参数3:指定观察者到视景体的最近的裁剪面的距离(正数)
- //参数4:指定观察者到视景体最远的裁剪面距离(正数)
- projection.perspective(45.0f, 1.0f * width() / height(), 0.1f, 100.0f);
- shaderProgram.setUniformValue("projection", projection);
- shaderProgram.release();
-
- timer.start();
-
- // 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);
-
- }
-
- void BKQOpenglW::resizeGL(int w, int h)
- {
- glViewport(0,0,w,h);
- }
-
- void BKQOpenglW::paintGL()
- {
-
- glEnable(GL_DEPTH_TEST);
- glClearColor(0.2f, 0.3f, 0.3f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-
-
- shaderProgram.setUniformValue("view", getViewMatrix());
-
-
- shaderProgram.bind();
- glBindVertexArray(VAO);
- switch (m_Shape) {
- case Triangle:
- glDrawArrays(GL_TRIANGLES,0,3);
- break;
- case Rect:
- pTexture->bind(0);
- pTexture2->bind(1);
-
- for (unsigned int i = 0; i < 10; i++) {
- //计算模型矩阵
- QMatrix4x4 model;
- //平移
- model.translate(cubePositions[i]);
- //这样每个箱子旋转的速度就不一样
- float angle = (i + 1.0f) * rotate;
- //旋转
- model.rotate(angle, QVector3D(1.0f, 0.3f, 0.5f));
- //传入着色器并绘制
- shaderProgram.setUniformValue("model", model);
- glDrawArrays(GL_TRIANGLES, 0, 36);
- }
- break;
- default:
- break;
- }
-
- }
-
- void BKQOpenglW::keyPressEvent(QKeyEvent *event)
- {
- event->accept();
- //横向是移动,不是绕0点
- switch (event->key()) {
- case Qt::Key_W: //摄像机往上,场景往下
- cameraPos -= QVector3D::crossProduct(cameraFront, cameraRight).normalized() * cameraSpeed;
- break;
- case Qt::Key_S: //摄像机往下,场景往上
- cameraPos += QVector3D::crossProduct(cameraFront, cameraRight).normalized() * cameraSpeed;
- break;
- case Qt::Key_A: //摄像机往左,场景往右
- cameraPos -= QVector3D::crossProduct(cameraFront, cameraUp).normalized() * cameraSpeed;
- break;
- case Qt::Key_D: //摄像机往右,场景往左
- cameraPos += QVector3D::crossProduct(cameraFront, cameraUp).normalized() * cameraSpeed;
- break;
- case Qt::Key_E: //远
- cameraPos -= cameraFront * cameraSpeed;
- break;
- case Qt::Key_Q: //近
- cameraPos += cameraFront * cameraSpeed;
- break;
- default:
- break;
- }
- update();
-
- }
-
- void BKQOpenglW::mousePressEvent(QMouseEvent *event)
- {
- event->accept();
- mousePos = event->pos();
- }
-
- void BKQOpenglW::mouseReleaseEvent(QMouseEvent *event)
- {
- event->accept();
- }
-
- void BKQOpenglW::mouseMoveEvent(QMouseEvent *event)
- {
- event->accept();
- int x_offset = event->pos().x()-mousePos.x();
- int y_offset = event->pos().y()-mousePos.y();
- mousePos = event->pos();
- //y轴的坐标是从下往上,所以相反
- //我这里移动的是摄像机,所以场景往相反方向动
- eulerYaw += x_offset*cameraSensitivity;
- eulerPitch -= y_offset*cameraSensitivity;
-
- if (eulerPitch > 89.0f)
- eulerPitch = 89.0f;
- else if (eulerPitch < -89.0f)
- eulerPitch = -89.0f;
- calculateCamera();
- update();
- }
-
- void BKQOpenglW::wheelEvent(QWheelEvent *event)
- {
- event->accept();
- //fovy越小,模型看起来越大
- if(event->delta() < 0){
- //鼠标向下滑动为-,这里作为zoom out
- projectionFovy += cameraSpeed;
- if(projectionFovy > 90)
- projectionFovy = 90;
- }else{
- //鼠标向上滑动为+,这里作为zoom in
- projectionFovy -= cameraSpeed;
- if(projectionFovy < 1)
- projectionFovy = 1;
- }
- update();
-
- }
-
- void BKQOpenglW::calculateCamera()
- {
- const float yaw = qDegreesToRadians(eulerYaw);
- const float pitch = qDegreesToRadians(eulerPitch);
- QVector3D front;
- front.setX(std::cos(yaw) * std::cos(pitch));
- front.setY(std::sin(pitch));
- front.setZ(std::sin(yaw) * std::cos(pitch));
- cameraFront = front.normalized();
- }
-
- QMatrix4x4 BKQOpenglW::getViewMatrix()
- {
- QMatrix4x4 view; //观察矩阵
- view.lookAt(cameraPos, cameraPos+cameraFront, cameraUp);
- return view;
- }
人生需要坚持下去,时间也会一点点给你回报,几个月没有更新了,以后要更加勤快。加油!