• QT中学习Opengl---(摄像机2)


    前言:

    本文的代码是 LearnOpenGL 中对应代码,这里提供学习,大家喜欢的可去官方网站去看看:

     LearnOpenGL-CNhttps://learnopengl-cn.readthedocs.io/zh/latest/

     本章讲解摄像机的移动。

    欧拉角

          欧拉角是表示3D空间中可以表示任何旋转的三个值, 由莱昂哈德·欧拉在18世纪提出。 有三种
    欧拉角: 俯仰角(Pitch)、 偏航角(Yaw)和滚转角(Roll), 下面的图片展示了它们的含义:

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

    代码部分

     顶点着色器:

    1. #version 330 core
    2. layout (location = 0) in vec3 aPos;
    3. layout (location = 1) in vec2 aTexCoord;
    4. out vec2 TexCoord;
    5. uniform mat4 model;
    6. uniform mat4 view;
    7. uniform mat4 projection;
    8. void main()
    9. {
    10. gl_Position =projection*view*model* vec4(aPos, 1.0);
    11. TexCoord = vec2(aTexCoord.x, aTexCoord.y);
    12. }

    片段着色器:

    1. #version 330 core
    2. out vec4 FragColor;
    3. in vec2 TexCoord;
    4. // texture samplers
    5. uniform sampler2D texture1;
    6. uniform sampler2D texture2;
    7. void main()
    8. {
    9. // linearly interpolate between both textures (80% container, 20% awesomeface)
    10. FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
    11. //FragColor =texture(texture2,TexCoord);
    12. }

    源码部分:

    1. #ifndef BKQOPENGLW_H
    2. #define BKQOPENGLW_H
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. class BKQOpenglW : public QOpenGLWidget, QOpenGLFunctions_3_3_Core
    13. {
    14. Q_OBJECT
    15. public:
    16. enum Shape{None,Rect,circle,Triangle};
    17. explicit BKQOpenglW(QWidget *parent = nullptr);
    18. ~BKQOpenglW();
    19. void drawShapes(Shape shape);
    20. void setWireFrame(bool b);
    21. protected:
    22. //设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
    23. virtual void initializeGL() override;
    24. //渲染OpenGL场景,每当需要更新小部件时使用
    25. virtual void resizeGL(int w, int h) override;
    26. //设置OpenGL视口、投影等,每当尺寸大小改变时调用
    27. virtual void paintGL() override;
    28. //键盘操作重载Qt的事件处理
    29. virtual void keyPressEvent(QKeyEvent *event) override;
    30. //鼠标操作,重载Qt的事件处理
    31. void mousePressEvent(QMouseEvent *event) override;
    32. void mouseReleaseEvent(QMouseEvent *event) override;
    33. void mouseMoveEvent(QMouseEvent *event) override;
    34. void wheelEvent(QWheelEvent *event) override;
    35. private:
    36. //计算
    37. void calculateCamera();
    38. QMatrix4x4 getViewMatrix();
    39. signals:
    40. public slots:
    41. private:
    42. unsigned int VBO, VAO,EBO;
    43. Shape m_Shape;
    44. QOpenGLShaderProgram shaderProgram;
    45. unsigned int texture;
    46. QOpenGLTexture *pTexture;
    47. QOpenGLTexture *pTexture2;
    48. QTimer timer;
    49. int rotate{ 0 };
    50. //鼠标位置
    51. QPoint mousePos;
    52. QVector3D cameraPos{ 0.0f, 0.0f, 3.0f };
    53. QVector3D cameraFront{ 0.0f, 0.0f, -1.0f };
    54. QVector3D cameraUp{ 0.0f, 1.0f, 0.0f };
    55. QVector3D cameraRight{ 1.0f, 0.0f, 0.0f };
    56. //Euler Angles
    57. //偏航角如果是0.0f,指向的是 x轴正方向,即右方向,所以向里转90度,初始方向指向z轴负方向
    58. float eulerYaw{ -90.0f }; //偏航角,绕y左右转
    59. float eulerPitch{ 0.0f }; //俯仰角,绕x上下转
    60. //Camera options
    61. float cameraSpeed{ 0.5f }; //移动速度
    62. float cameraSensitivity{ 0.1f }; //鼠标拖动灵敏度
    63. float projectionFovy{ 45.0f }; //透视投影的fovy参数,视野范围
    64. };
    65. #endif // BKQOPENGLW_H

    对应cpp

    1. #include "bkqopenglw.h"
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define STB_IMAGE_IMPLEMENTATION
    8. #include "stb_image.h"
    9. #if 0
    10. float vertices[] = {
    11. // positions // colors // texture coords
    12. 0.8f, 0.8f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, // top right
    13. 0.8f, -0.8f, 0.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, // bottom right
    14. -0.8f, -0.8f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
    15. -0.8f, 0.8f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 2.0f // top left
    16. };
    17. #endif
    18. //顶点数据(盒子六个面,一个面两个三角)
    19. float vertices[] = {
    20. -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    21. 0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
    22. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    23. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    24. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    25. -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    26. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    27. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    28. 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    29. 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    30. -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
    31. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    32. -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    33. -0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    34. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    35. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    36. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    37. -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    38. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    39. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    40. 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    41. 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    42. 0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    43. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    44. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    45. 0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
    46. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    47. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    48. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    49. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    50. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    51. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    52. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    53. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    54. -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
    55. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
    56. };
    57. unsigned int indices[] = { // note that we start from 0!
    58. 0, 1, 3, // first Triangle
    59. 1, 2, 3 // second Triangle
    60. };
    61. //绘制多个盒子
    62. static QVector3D cubePositions[] = {
    63. QVector3D( 0.0f, 0.0f, 0.0f),
    64. QVector3D( 2.0f, 5.0f, -15.0f),
    65. QVector3D(-1.5f, -2.2f, -2.5f),
    66. QVector3D(-3.8f, -2.0f, -12.3f),
    67. QVector3D( 2.4f, -0.4f, -3.5f),
    68. QVector3D(-1.7f, 3.0f, -7.5f),
    69. QVector3D( 1.3f, -2.0f, -2.5f),
    70. QVector3D( 1.5f, 2.0f, -2.5f),
    71. QVector3D( 1.5f, 0.2f, -1.5f),
    72. QVector3D(-1.3f, 1.0f, -1.5f)
    73. };
    74. BKQOpenglW::BKQOpenglW(QWidget *parent) : QOpenGLWidget(parent)
    75. {
    76. setFocusPolicy(Qt::StrongFocus);
    77. // QSurfaceFormat fmt = format();
    78. // fmt.setRenderableType(QSurfaceFormat::OpenGL);
    79. // fmt.setProfile(QSurfaceFormat::CoreProfile);
    80. fmt.setVersion(3, 3);
    81. // //当启用多重采样时,将每个像素的首选样本数设置为numSamples
    82. // fmt.setSamples(4);
    83. // setFormat(fmt);
    84. connect(&timer,&QTimer::timeout,this,[this](){
    85. rotate+=2;
    86. if(isVisible()){
    87. update();
    88. }
    89. });
    90. timer.setInterval(50);
    91. //弧度转换
    92. calculateCamera();
    93. }
    94. BKQOpenglW::~BKQOpenglW()
    95. {
    96. makeCurrent();
    97. glDeleteVertexArrays(1,&VAO);
    98. glDeleteBuffers(1,&VBO);
    99. doneCurrent();
    100. }
    101. void BKQOpenglW::drawShapes(BKQOpenglW::Shape shape)
    102. {
    103. m_Shape = shape;
    104. update();
    105. }
    106. void BKQOpenglW::setWireFrame(bool b)
    107. {
    108. makeCurrent();
    109. if(b)
    110. {
    111. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    112. }
    113. else {
    114. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    115. }
    116. update();
    117. doneCurrent();
    118. }
    119. void BKQOpenglW::initializeGL()
    120. {
    121. initializeOpenGLFunctions();
    122. // shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,vertexShaderSource);
    123. // shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,fragmentShaderSource);
    124. shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/shader.vs");
    125. shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/shader.fs");
    126. shaderProgram.link();
    127. glGenVertexArrays(1, &VAO);
    128. glGenBuffers(1, &VBO);
    129. // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    130. glBindVertexArray(VAO);
    131. glBindBuffer(GL_ARRAY_BUFFER, VBO);
    132. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    133. //绑定ebo
    134. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    135. glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW);
    136. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
    137. glEnableVertexAttribArray(0);
    138. // texture coord attribute
    139. glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    140. glEnableVertexAttribArray(1);
    141. //绑定纹理
    142. glEnable(GL_BLEND);
    143. glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    144. pTexture = new QOpenGLTexture(QImage(":/images/images/brickwall.jpg").mirrored());
    145. pTexture2 = new QOpenGLTexture(QImage(":/images/images/awesomeface.png").mirrored());
    146. shaderProgram.bind();
    147. shaderProgram.setUniformValue("texture1",0);
    148. shaderProgram.setUniformValue("texture2",1);
    149. //默认为GL_REPEAT 重复 GL_MIRRORED_REPEAT镜像 GL_CLAMP_TO_EDGE 边缘拉伸 GL_CLAMP_TO_BORDER 超出部分使用用户定义
    150. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_REPEAT); // we want to repeat the awesomeface pattern so we kept it at GL_REPEAT
    151. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_REPEAT);
    152. QMatrix4x4 projection; //透视投影
    153. //坐标到达观察空间之后,我们需要将其投影到裁剪坐标。
    154. //裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上
    155. //参数1:指定视景体的视野的角度
    156. //参数2:指定你的视景体的宽高比
    157. //参数3:指定观察者到视景体的最近的裁剪面的距离(正数)
    158. //参数4:指定观察者到视景体最远的裁剪面距离(正数)
    159. projection.perspective(45.0f, 1.0f * width() / height(), 0.1f, 100.0f);
    160. shaderProgram.setUniformValue("projection", projection);
    161. shaderProgram.release();
    162. timer.start();
    163. // 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
    164. glBindBuffer(GL_ARRAY_BUFFER, 0);
    165. // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    166. // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    167. glBindVertexArray(0);
    168. }
    169. void BKQOpenglW::resizeGL(int w, int h)
    170. {
    171. glViewport(0,0,w,h);
    172. }
    173. void BKQOpenglW::paintGL()
    174. {
    175. glEnable(GL_DEPTH_TEST);
    176. glClearColor(0.2f, 0.3f, 0.3f, 0.0f);
    177. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    178. shaderProgram.setUniformValue("view", getViewMatrix());
    179. shaderProgram.bind();
    180. glBindVertexArray(VAO);
    181. switch (m_Shape) {
    182. case Triangle:
    183. glDrawArrays(GL_TRIANGLES,0,3);
    184. break;
    185. case Rect:
    186. pTexture->bind(0);
    187. pTexture2->bind(1);
    188. for (unsigned int i = 0; i < 10; i++) {
    189. //计算模型矩阵
    190. QMatrix4x4 model;
    191. //平移
    192. model.translate(cubePositions[i]);
    193. //这样每个箱子旋转的速度就不一样
    194. float angle = (i + 1.0f) * rotate;
    195. //旋转
    196. model.rotate(angle, QVector3D(1.0f, 0.3f, 0.5f));
    197. //传入着色器并绘制
    198. shaderProgram.setUniformValue("model", model);
    199. glDrawArrays(GL_TRIANGLES, 0, 36);
    200. }
    201. break;
    202. default:
    203. break;
    204. }
    205. }
    206. void BKQOpenglW::keyPressEvent(QKeyEvent *event)
    207. {
    208. event->accept();
    209. //横向是移动,不是绕0点
    210. switch (event->key()) {
    211. case Qt::Key_W: //摄像机往上,场景往下
    212. cameraPos -= QVector3D::crossProduct(cameraFront, cameraRight).normalized() * cameraSpeed;
    213. break;
    214. case Qt::Key_S: //摄像机往下,场景往上
    215. cameraPos += QVector3D::crossProduct(cameraFront, cameraRight).normalized() * cameraSpeed;
    216. break;
    217. case Qt::Key_A: //摄像机往左,场景往右
    218. cameraPos -= QVector3D::crossProduct(cameraFront, cameraUp).normalized() * cameraSpeed;
    219. break;
    220. case Qt::Key_D: //摄像机往右,场景往左
    221. cameraPos += QVector3D::crossProduct(cameraFront, cameraUp).normalized() * cameraSpeed;
    222. break;
    223. case Qt::Key_E: //远
    224. cameraPos -= cameraFront * cameraSpeed;
    225. break;
    226. case Qt::Key_Q: //近
    227. cameraPos += cameraFront * cameraSpeed;
    228. break;
    229. default:
    230. break;
    231. }
    232. update();
    233. }
    234. void BKQOpenglW::mousePressEvent(QMouseEvent *event)
    235. {
    236. event->accept();
    237. mousePos = event->pos();
    238. }
    239. void BKQOpenglW::mouseReleaseEvent(QMouseEvent *event)
    240. {
    241. event->accept();
    242. }
    243. void BKQOpenglW::mouseMoveEvent(QMouseEvent *event)
    244. {
    245. event->accept();
    246. int x_offset = event->pos().x()-mousePos.x();
    247. int y_offset = event->pos().y()-mousePos.y();
    248. mousePos = event->pos();
    249. //y轴的坐标是从下往上,所以相反
    250. //我这里移动的是摄像机,所以场景往相反方向动
    251. eulerYaw += x_offset*cameraSensitivity;
    252. eulerPitch -= y_offset*cameraSensitivity;
    253. if (eulerPitch > 89.0f)
    254. eulerPitch = 89.0f;
    255. else if (eulerPitch < -89.0f)
    256. eulerPitch = -89.0f;
    257. calculateCamera();
    258. update();
    259. }
    260. void BKQOpenglW::wheelEvent(QWheelEvent *event)
    261. {
    262. event->accept();
    263. //fovy越小,模型看起来越大
    264. if(event->delta() < 0){
    265. //鼠标向下滑动为-,这里作为zoom out
    266. projectionFovy += cameraSpeed;
    267. if(projectionFovy > 90)
    268. projectionFovy = 90;
    269. }else{
    270. //鼠标向上滑动为+,这里作为zoom in
    271. projectionFovy -= cameraSpeed;
    272. if(projectionFovy < 1)
    273. projectionFovy = 1;
    274. }
    275. update();
    276. }
    277. void BKQOpenglW::calculateCamera()
    278. {
    279. const float yaw = qDegreesToRadians(eulerYaw);
    280. const float pitch = qDegreesToRadians(eulerPitch);
    281. QVector3D front;
    282. front.setX(std::cos(yaw) * std::cos(pitch));
    283. front.setY(std::sin(pitch));
    284. front.setZ(std::sin(yaw) * std::cos(pitch));
    285. cameraFront = front.normalized();
    286. }
    287. QMatrix4x4 BKQOpenglW::getViewMatrix()
    288. {
    289. QMatrix4x4 view; //观察矩阵
    290. view.lookAt(cameraPos, cameraPos+cameraFront, cameraUp);
    291. return view;
    292. }

    后面的话

         人生需要坚持下去,时间也会一点点给你回报,几个月没有更新了,以后要更加勤快。加油! 

  • 相关阅读:
    美团一面复活赛4/18
    前端面试指南之React篇(一)
    iPhone苹果手机iOS16剪贴板复制粘贴确认弹窗怎么关闭清理剪切板提醒设置方法的教程?
    Windows服务器TLS协议
    基于Gradio/Stable Diffusion/Midjourney的AIGC自动图像绘画生成软件 - Fooocus
    C6000教学实验箱_嵌入式操作教程_音频编码:3-7 G711A音频编码实验
    JDBC中execute、executeQuery和executeUpdate的区别
    操作系统 | 内存管理
    多任务联合训练,出现Nan的问题
    PLONK 的工作原理:第 1 部分
  • 原文地址:https://blog.csdn.net/weixin_42126427/article/details/126147705