• OpenGL原理与实践——核心模式(四):摄像机变换理论与应用


    目录

    变换是什么?对于OpenGL的摄像机又意味着什么?

    MVP变换

    投影变换

    正交投影变换

    透视投影变换 

    摄像机/投影矩阵的应用

    绘制单个立方体——源码及渲染结果

    绘制多个立方体——源码及渲染结果

    构建摄像机类——实现控制摄像机移动

    摄像机坐标系的构成

    摄像机坐标系的参数构建

    摄像机关键参数提取(移动参数)

    摄像机平移功能实现

    构建摄像机类——实现控制摄像机旋转

    摄像机front向量的xyz

    鼠标跟踪控制方法分解 

    摄像机旋转功能实现


    变换是什么?对于OpenGL的摄像机又意味着什么?

    答:就是将三维物体映射到摄像机屏幕的过程。

     在线性代数中,变换=矩阵,任何3D变化都可以通过矩阵来表示。 

    MVP变换

    那么问题来了,如何将三维物体映射到屏幕空间呢?

    答:经过MVP变换。

    这里不对MVP变换做过多的展开,详细理论可参考GAMES101的课程。

    那么如何变换呢?如何获得物体在观察坐标系下的位置呢?

    不失一般性,我们考虑一个简单的情况,即观察坐标系与世界坐标系平行:

    •  首先我们将观察坐标系平移变换到世界坐标系原点,那么会有一个对应的矩阵
    • 我们用同样的矩阵,对物体做一次变换,即可得到物体在观察坐标系下的位置

    但更一般的情况是:摄像机空间与世界空间存在一定的角度:

    那此时如何得到物体在摄像机空间的相对位置呢?

    答:可以将摄像机移动到世界坐标系原点,然后将摄像机坐标系的三个正交基旋转至与世界坐标系重合。

    但问题来了,如何获得这个旋转矩阵呢?这个矩阵并不好算。

    但我们可以曲线救国,利用矩阵的逆。

    既然直接求摄像机空间旋转至世界空间不好求,那我们可以把世界空间旋转至摄像机空间,并获得一个矩阵,然后再求这个矩阵的逆,即为摄像机空间旋转至世界空间的变换矩阵。

    投影变换

    投影分两种:

    投影变换的目标是:将空间中的点P变换到摄像机平面坐标系内,并且做成NDC(标准设备坐标)的形式。NDC为了兼容不同窗口的宽高,让x与y的都同一到(-1,1)范围内,之后各自乘以宽高

    正交投影变换

    透视投影变换 

     

    空间中的点投射到屏幕近剪裁平面的坐标。

    过多的数学推导这里不做展示,直接给出结果:

    摄像机/投影矩阵的应用

    下载并载入glm第三方库:

    类似之前实践的思路,我们需要更改和设置:

    • 设置glm::mat4 初始化view摄像机矩阵和proj投影矩阵
    • 设置好需要绘制的正方体六个面
    • 处理相应锚点并激活,这里不需要索引处理了
    • 在shader中添加设置矩阵的方法
    • 在render()中,利用glm设置相应矩阵,并开启深度测试

    绘制单个立方体——源码及渲染结果

    1. #include "Base.h"
    2. #include "Shader.h"
    3. #include "ffImage.h"
    4. void framebuffer_size_callback(GLFWwindow* window, int width, int height);
    5. void processInput(GLFWwindow* window);
    6. void initModel();
    7. void initShader(const char* _vertexPath, const char* _fragPath);
    8. void initTexture();
    9. void render();
    10. unsigned int VBO = 0;
    11. unsigned int VAO = 0;
    12. unsigned int EBO = 0;
    13. unsigned int _texture = 0;
    14. Shader _shader;
    15. ffImage* _pImage = nullptr;
    16. glm::mat4 _viewMatrix(1.0f);
    17. glm::mat4 _projMatrix(1.0f);
    18. int _width = 800;
    19. int _height = 600;
    20. int main() {
    21. //初始化OpenGL上下文环境,OpenGL是一个状态机,会保存当前状态下的渲染状态以及管线的状态
    22. glfwInit();
    23. //,3版本以上
    24. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    25. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    26. //用OpenGL核心开发模式
    27. glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
    28. //创建窗体
    29. GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGl Core", nullptr, nullptr);
    30. if (window == nullptr) {
    31. std::cout << "Failed to create GLFW window" << std::endl;
    32. glfwTerminate();
    33. return -1;
    34. }
    35. //把当前上下文绑定至当前窗口
    36. glfwMakeContextCurrent(window);
    37. //通过glad绑定各种函数指针
    38. if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
    39. std::cout << "Failed to initialize GLAD" << std::endl;
    40. return -1;
    41. }
    42. //视口:需要渲染的东西在哪里
    43. glViewport(0, 0, _width, _height);
    44. //当Frame大小变动,调用回调函数调整视口大小
    45. glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    46. initModel();
    47. initShader("vertexShader.glsl", "fragmentShader.glsl");
    48. initTexture();
    49. //防止窗口结束退出
    50. while (!glfwWindowShouldClose(window)) {
    51. processInput(window);
    52. render();
    53. //双缓冲
    54. glfwSwapBuffers(window);
    55. glfwPollEvents();
    56. }
    57. //结束,释放资源
    58. glfwTerminate();
    59. return 0;
    60. }
    61. void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
    62. glViewport(0, 0, width, height);
    63. }
    64. void processInput(GLFWwindow* window) {
    65. if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
    66. glfwSetWindowShouldClose(window, true);
    67. }
    68. }
    69. //渲染
    70. void render() {
    71. //擦除画布,用定义的颜色填充
    72. glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    73. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    74. glEnable(GL_DEPTH_TEST);
    75. //眼睛(摄像机)位置,看向位置,摄像机上方位置
    76. _viewMatrix = glm::lookAt(
    77. glm::vec3(3.0f, 3.0f, 3.0f),
    78. glm::vec3(0.0f, 0.0f, 0.0f),
    79. glm::vec3(0.0f, 1.0f, 0.0f));
    80. //透视投影矩阵:视锥角,宽高比,近平面,远平面
    81. _projMatrix = glm::perspective(
    82. glm::radians(45.0f),
    83. (float)_width / (float)_height,
    84. 0.1f,
    85. 100.0f);
    86. glBindTexture(GL_TEXTURE_2D, _texture);
    87. _shader.start();
    88. _shader.setMatrix("_viewMatrix", _viewMatrix);
    89. _shader.setMatrix("_projMatrix", _projMatrix);
    90. glBindVertexArray(VAO);
    91. glDrawArrays(GL_TRIANGLES, 0, 36);
    92. _shader.end();
    93. }
    94. //构建模型数据:VBO,VAO
    95. void initModel() {
    96. //float vertices[] = {
    97. // //顶点信息 颜色信息 纹理信息
    98. // 0.5f, 0.5f, 0.0f, 1.0f,0.0f,0.0f, 1.0f,1.0f,
    99. // 0.5f, -0.5f, 0.0f, 0.0f,1.0f,0.0f, 1.0f,0.0f,
    100. // -0.5f, -0.5f, 0.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,
    101. // -0.5f, 0.5f, 0.0f, 0.0f,1.0f,0.0f, 0.0f,1.0f
    102. //};
    103. float vertices[] = {
    104. //第一个面,六个顶点两个三角形
    105. -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    106. 0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
    107. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    108. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    109. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    110. -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    111. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    112. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    113. 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    114. 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    115. -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
    116. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    117. -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    118. -0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    119. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    120. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    121. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    122. -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    123. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    124. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    125. 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    126. 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    127. 0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    128. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    129. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    130. 0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
    131. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    132. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    133. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    134. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    135. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    136. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    137. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    138. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    139. -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
    140. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
    141. };
    142. glGenVertexArrays(1, &VAO);
    143. glBindVertexArray(VAO);
    144. //之后的VBO便属于了VAO的管理范围
    145. glGenBuffers(1, &VBO);
    146. //绑定哪一种buffer,
    147. glBindBuffer(GL_ARRAY_BUFFER, VBO);
    148. //分配显存:分配哪种buffer,分配显存大小,分配地址,使用数据的方式
    149. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    150. //对哪个锚点进行操作:layout=0的锚点,读3个顶点,类型为float,不需要归一化,每次步长为3个float大小,从0处开始读
    151. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    152. glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(sizeof(float)*3));
    153. //打开锚点:激活
    154. glEnableVertexAttribArray(0);
    155. glEnableVertexAttribArray(1);
    156. //解绑
    157. glBindBuffer(GL_ARRAY_BUFFER, 0);
    158. glBindVertexArray(0);
    159. }
    160. //
    161. void initShader(const char* _vertexPath, const char* _fragPath) {
    162. _shader.initShader(_vertexPath, _fragPath);
    163. }
    164. void initTexture() {
    165. _pImage = ffImage::readFromFile("res/wall.jpg");
    166. //纹理绑定
    167. glGenTextures(1, &_texture);
    168. glBindTexture(GL_TEXTURE_2D, _texture);
    169. //纹理属性设置
    170. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    171. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    172. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    173. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    174. //读入图片数据
    175. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _pImage->getWidth(), _pImage->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE,_pImage->getData());
    176. }
    1. //vertexShader.glsl
    2. #version 330 core
    3. layout (location = 0) in vec3 aPos;
    4. layout (location = 1) in vec2 aUV;
    5. out vec2 outUV;
    6. uniform mat4 _modelMatrix;
    7. uniform mat4 _viewMatrix;
    8. uniform mat4 _projMatrix;
    9. void main()
    10. {
    11. gl_Position = _projMatrix * _viewMatrix * _modelMatrix * vec4(aPos.x, aPos.y, aPos.z, 1.0);
    12. outUV = aUV;
    13. };
    1. //fragmentShader.glsl
    2. #version 330 core
    3. out vec4 FragColor;
    4. in vec2 outUV;
    5. uniform sampler2D outTexture;
    6. void main()
    7. {
    8. FragColor = texture(outTexture, outUV) ;
    9. };

    绘制多个立方体——源码及渲染结果

    这里绘制10个立方体,对每一个立方体先进行一个平移操作,并且进行旋转操作

    1. //渲染
    2. void render() {
    3. //擦除画布,用定义的颜色填充
    4. glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    5. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    6. glEnable(GL_DEPTH_TEST);
    7. glm::vec3 modelVecs[] = {
    8. glm::vec3(0.0f, 0.0f, 0.0f),
    9. glm::vec3(2.0f, 5.0f, -15.0f),
    10. glm::vec3(-1.5f, -2.2f, -2.5f),
    11. glm::vec3(-3.8f, -2.0f, -12.3f),
    12. glm::vec3(2.4f, -0.4f, -3.5f),
    13. glm::vec3(-1.7f, 3.0f, -7.5f),
    14. glm::vec3(1.3f, -2.0f, -2.5f),
    15. glm::vec3(1.5f, 2.0f, -2.5f),
    16. glm::vec3(1.5f, 0.2f, -1.5f),
    17. glm::vec3(-1.3f, 1.0f, -1.5f)
    18. };
    19. _viewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    20. _projMatrix = glm::perspective(glm::radians(45.0f), (float)_width / (float)_height, 0.1f, 100.0f);
    21. glBindTexture(GL_TEXTURE_2D, _texture);
    22. for (int i = 0; i < 10; i++)
    23. {
    24. glm::mat4 _modelMatrix(1.0f);//单位阵
    25. _modelMatrix = glm::translate(_modelMatrix, modelVecs[i]);//平移
    26. _modelMatrix = glm::rotate(_modelMatrix, glm::radians((float)glfwGetTime() * (i + 1) * 10), glm::vec3(0.0f, 1.0f, 0.0f));
    27. _shader.start();
    28. _shader.setMatrix("_modelMatrix", _modelMatrix);
    29. _shader.setMatrix("_viewMatrix", _viewMatrix);
    30. _shader.setMatrix("_projMatrix", _projMatrix);
    31. glBindVertexArray(VAO);
    32. glDrawArrays(GL_TRIANGLES, 0, 36);
    33. _shader.end();
    34. }
    35. }

     

    构建摄像机类——实现控制摄像机移动

    需要完成的任务:

    • 接受鼠标以及键盘的信息,并做出反馈
    • 提供接口,控制摄像机上下左右观望、前后左右移动

    摄像机坐标系的构成

    • 确定位置:Position
    • 确定朝向:与世界坐标系做连线,但相反的方向作为z轴
    • 确定右方:人为规定一个up向量,比如世界坐标的y轴,与摄像机空间z轴做叉乘,得到right向量
    • 确定上方:通过已求得的两个向量right和direction,叉乘获得up向量

    摄像机坐标系的参数构建

     

    摄像机关键参数提取(移动参数)

    摄像机平移功能实现

    摄像机类:

    1. //Camera.h
    2. #pragma once
    3. #include "Base.h"
    4. enum class CAMERA_MOVE{
    5. MOVE_LEFT,
    6. MOVE_RIGHT,
    7. MOVE_FRONT,
    8. MOVE_BACK
    9. };
    10. class Camera
    11. {
    12. private:
    13. glm::vec3 m_position;
    14. glm::vec3 m_front;
    15. glm::vec3 m_up;
    16. float m_speed;
    17. glm::mat4 m_vMatrix;
    18. public:
    19. Camera() {
    20. m_position = glm::vec3(1.0f);
    21. m_front= glm::vec3(1.0f);
    22. m_up = glm::vec3(1.0f);
    23. m_speed = 0.01f;
    24. m_vMatrix = glm::mat4(1.0f);
    25. }
    26. ~Camera() {}
    27. void lookAt(glm::vec3 _pos, glm::vec3 _front, glm::vec3 _up);
    28. void update();
    29. glm::mat4 getMatrix() { return m_vMatrix; }
    30. void move(CAMERA_MOVE _mode);
    31. void setspeed(float _speed);
    32. };
    1. //Camera.cpp
    2. #include "Camera.h"
    3. void Camera::lookAt(glm::vec3 _pos, glm::vec3 _front, glm::vec3 _up)
    4. {
    5. m_position = _pos;
    6. m_front = glm::normalize(_front);
    7. m_up = _up;
    8. m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
    9. }
    10. void Camera::update()
    11. {
    12. m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
    13. }
    14. void Camera::move(CAMERA_MOVE _mode)
    15. {
    16. switch (_mode)
    17. {
    18. case CAMERA_MOVE::MOVE_LEFT:
    19. m_position -= glm::normalize(glm::cross(m_front, m_up)) * m_speed;
    20. break;
    21. case CAMERA_MOVE::MOVE_RIGHT:
    22. m_position += glm::normalize(glm::cross(m_front, m_up)) * m_speed;
    23. break;
    24. case CAMERA_MOVE::MOVE_FRONT:
    25. m_position += m_speed * m_front;
    26. break;
    27. case CAMERA_MOVE::MOVE_BACK:
    28. m_position -= m_speed * m_front;
    29. break;
    30. default:
    31. break;
    32. }
    33. }
    34. void Camera::setspeed(float _speed)
    35. {
    36. m_speed = _speed;
    37. }

     main.cpp:

    1. #include "Base.h"
    2. #include "Shader.h"
    3. #include "ffImage.h"
    4. #include "Camera.h"
    5. void framebuffer_size_callback(GLFWwindow* window, int width, int height);
    6. void processInput(GLFWwindow* window);
    7. void initModel();
    8. void initShader(const char* _vertexPath, const char* _fragPath);
    9. void initTexture();
    10. void render();
    11. unsigned int VBO = 0;
    12. unsigned int VAO = 0;
    13. unsigned int EBO = 0;
    14. unsigned int _texture = 0;
    15. Shader _shader;
    16. ffImage* _pImage = nullptr;
    17. Camera _camera;
    18. glm::mat4 _projMatrix(1.0f);
    19. int _width = 800;
    20. int _height = 600;
    21. int main() {
    22. //初始化OpenGL上下文环境,OpenGL是一个状态机,会保存当前状态下的渲染状态以及管线的状态
    23. glfwInit();
    24. //,3版本以上
    25. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    26. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    27. //用OpenGL核心开发模式
    28. glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
    29. //创建窗体
    30. GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGl Core", nullptr, nullptr);
    31. if (window == nullptr) {
    32. std::cout << "Failed to create GLFW window" << std::endl;
    33. glfwTerminate();
    34. return -1;
    35. }
    36. //把当前上下文绑定至当前窗口
    37. glfwMakeContextCurrent(window);
    38. //通过glad绑定各种函数指针
    39. if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
    40. std::cout << "Failed to initialize GLAD" << std::endl;
    41. return -1;
    42. }
    43. //视口:需要渲染的东西在哪里
    44. glViewport(0, 0, _width, _height);
    45. //当Frame大小变动,调用回调函数调整视口大小
    46. glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    47. _camera.lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    48. _camera.setspeed(0.01f);
    49. initModel();
    50. initShader("vertexShader.glsl", "fragmentShader.glsl");
    51. initTexture();
    52. //防止窗口结束退出
    53. while (!glfwWindowShouldClose(window)) {
    54. processInput(window);
    55. render();
    56. //双缓冲
    57. glfwSwapBuffers(window);
    58. glfwPollEvents();
    59. }
    60. //结束,释放资源
    61. glfwTerminate();
    62. return 0;
    63. }
    64. void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
    65. glViewport(0, 0, width, height);
    66. }
    67. void processInput(GLFWwindow* window) {
    68. if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
    69. glfwSetWindowShouldClose(window, true);
    70. }
    71. if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
    72. _camera.move(CAMERA_MOVE::MOVE_FRONT);
    73. }
    74. if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
    75. _camera.move(CAMERA_MOVE::MOVE_BACK);
    76. }
    77. if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
    78. _camera.move(CAMERA_MOVE::MOVE_LEFT);
    79. }
    80. if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
    81. _camera.move(CAMERA_MOVE::MOVE_RIGHT);
    82. }
    83. }
    84. //渲染
    85. void render() {
    86. //擦除画布,用定义的颜色填充
    87. glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    88. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    89. glEnable(GL_DEPTH_TEST);
    90. glm::vec3 modelVecs[] = {
    91. glm::vec3(0.0f, 0.0f, 0.0f),
    92. glm::vec3(2.0f, 5.0f, -15.0f),
    93. glm::vec3(-1.5f, -2.2f, -2.5f),
    94. glm::vec3(-3.8f, -2.0f, -12.3f),
    95. glm::vec3(2.4f, -0.4f, -3.5f),
    96. glm::vec3(-1.7f, 3.0f, -7.5f),
    97. glm::vec3(1.3f, -2.0f, -2.5f),
    98. glm::vec3(1.5f, 2.0f, -2.5f),
    99. glm::vec3(1.5f, 0.2f, -1.5f),
    100. glm::vec3(-1.3f, 1.0f, -1.5f)
    101. };
    102. _camera.update();
    103. _projMatrix = glm::perspective(glm::radians(45.0f), (float)_width / (float)_height, 0.1f, 100.0f);
    104. glBindTexture(GL_TEXTURE_2D, _texture);
    105. for (int i = 0; i < 10; i++)
    106. {
    107. glm::mat4 _modelMatrix(1.0f);//单位阵
    108. _modelMatrix = glm::translate(_modelMatrix, modelVecs[i]);//平移
    109. _modelMatrix = glm::rotate(_modelMatrix, glm::radians((float)glfwGetTime() * (i + 1) * 10), glm::vec3(0.0f, 1.0f, 0.0f));//绕y轴旋转
    110. _shader.start();
    111. _shader.setMatrix("_modelMatrix", _modelMatrix);
    112. _shader.setMatrix("_viewMatrix", _camera.getMatrix());
    113. _shader.setMatrix("_projMatrix", _projMatrix);
    114. glBindVertexArray(VAO);
    115. glDrawArrays(GL_TRIANGLES, 0, 36);
    116. _shader.end();
    117. }
    118. }
    119. //构建模型数据:VBO,VAO
    120. void initModel() {
    121. //float vertices[] = {
    122. // //顶点信息 颜色信息 纹理信息
    123. // 0.5f, 0.5f, 0.0f, 1.0f,0.0f,0.0f, 1.0f,1.0f,
    124. // 0.5f, -0.5f, 0.0f, 0.0f,1.0f,0.0f, 1.0f,0.0f,
    125. // -0.5f, -0.5f, 0.0f, 0.0f,0.0f,1.0f, 0.0f,0.0f,
    126. // -0.5f, 0.5f, 0.0f, 0.0f,1.0f,0.0f, 0.0f,1.0f
    127. //};
    128. float vertices[] = {
    129. //第一个面,六个顶点两个三角形
    130. -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    131. 0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
    132. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    133. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    134. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    135. -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
    136. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    137. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    138. 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    139. 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    140. -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
    141. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    142. -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    143. -0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    144. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    145. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    146. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    147. -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    148. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    149. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    150. 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    151. 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    152. 0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    153. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    154. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    155. 0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
    156. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    157. 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    158. -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    159. -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
    160. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
    161. 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
    162. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    163. 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    164. -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
    165. -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
    166. };
    167. glGenVertexArrays(1, &VAO);
    168. glBindVertexArray(VAO);
    169. //之后的VBO便属于了VAO的管理范围
    170. glGenBuffers(1, &VBO);
    171. //绑定哪一种buffer,
    172. glBindBuffer(GL_ARRAY_BUFFER, VBO);
    173. //分配显存:分配哪种buffer,分配显存大小,分配地址,使用数据的方式
    174. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    175. //对哪个锚点进行操作:layout=0的锚点,读3个顶点,类型为float,不需要归一化,每次步长为3个float大小,从0处开始读
    176. glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    177. glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(sizeof(float)*3));
    178. //打开锚点:激活
    179. glEnableVertexAttribArray(0);
    180. glEnableVertexAttribArray(1);
    181. //解绑
    182. glBindBuffer(GL_ARRAY_BUFFER, 0);
    183. glBindVertexArray(0);
    184. }
    185. //
    186. void initShader(const char* _vertexPath, const char* _fragPath) {
    187. _shader.initShader(_vertexPath, _fragPath);
    188. }
    189. void initTexture() {
    190. _pImage = ffImage::readFromFile("res/wall.jpg");
    191. //纹理绑定
    192. glGenTextures(1, &_texture);
    193. glBindTexture(GL_TEXTURE_2D, _texture);
    194. //纹理属性设置
    195. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    196. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    197. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    198. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    199. //读入图片数据
    200. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _pImage->getWidth(), _pImage->getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE,_pImage->getData());
    201. }

    结果:

    构建摄像机类——实现控制摄像机旋转

    摄像机front向量的xyz

    front.y:

    front.x 和 front.z:

    计算方式:

    鼠标跟踪控制方法分解 

    摄像机旋转功能实现

    • 在主函数中设置鼠标模式,同时绑定回调函数
    • 在摄像机类中添加相应属性及方法
    • 根据之前的理论,编写代码计算个方向向量,并归一化
    • 在鼠标移动时,计算pitch和yaw角度的变化
    1. //Camera.cpp
    2. #include "Camera.h"
    3. void Camera::lookAt(glm::vec3 _pos, glm::vec3 _front, glm::vec3 _up)
    4. {
    5. m_position = _pos;
    6. m_front = glm::normalize(_front);
    7. m_up = _up;
    8. m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
    9. }
    10. void Camera::update()
    11. {
    12. m_vMatrix = glm::lookAt(m_position, m_position + m_front, m_up);
    13. }
    14. void Camera::move(CAMERA_MOVE _mode)
    15. {
    16. switch (_mode)
    17. {
    18. case CAMERA_MOVE::MOVE_LEFT:
    19. m_position -= glm::normalize(glm::cross(m_front, m_up)) * m_speed;
    20. break;
    21. case CAMERA_MOVE::MOVE_RIGHT:
    22. m_position += glm::normalize(glm::cross(m_front, m_up)) * m_speed;
    23. break;
    24. case CAMERA_MOVE::MOVE_FRONT:
    25. m_position += m_speed * m_front;
    26. break;
    27. case CAMERA_MOVE::MOVE_BACK:
    28. m_position -= m_speed * m_front;
    29. break;
    30. default:
    31. break;
    32. }
    33. }
    34. void Camera::setspeed(float _speed)
    35. {
    36. m_speed = _speed;
    37. }
    38. void Camera::pitch(float _yOffset)
    39. {
    40. m_pitch += _yOffset * m_sensitivity;
    41. if (m_pitch >= 89.0f) {
    42. m_pitch = 89.0f;
    43. }
    44. if (m_pitch <= -89.0f) {
    45. m_pitch = -89.0f;
    46. }
    47. m_front.y = sin(glm::radians(m_pitch));
    48. m_front.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));
    49. m_front.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));
    50. m_front = glm::normalize(m_front);
    51. update();
    52. }
    53. void Camera::yaw(float _xOffset)
    54. {
    55. m_yaw += _xOffset * m_sensitivity;
    56. m_front.y = sin(glm::radians(m_pitch));
    57. m_front.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));
    58. m_front.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));
    59. m_front = glm::normalize(m_front);
    60. update();
    61. }
    62. void Camera::setSensitivity(float _s)
    63. {
    64. m_sensitivity = _s;
    65. }
    66. void Camera::onMouseMove(double _xpos, double _ypos)
    67. {
    68. if (m_firseMove) {
    69. m_xpos = m_xpos;
    70. m_ypos = m_ypos;
    71. m_firseMove = false;
    72. return;
    73. }
    74. float _xOffset = _xpos - m_xpos;
    75. float _yOffset = -(_ypos - m_ypos);
    76. m_xpos = _xpos;
    77. m_ypos = _ypos;
    78. pitch(_yOffset);
    79. yaw(_xOffset);
    80. }

  • 相关阅读:
    数字电路笔记总结(一)(数制与编码)
    Java进阶篇--Condition与等待通知机制
    Cocos creator实现《滑雪趣挑战》滑雪小游戏资源及代码
    聊聊logback的EvaluatorFilter
    Java @NotBlank反射校验
    gan, pixel2pixel, cyclegan, srgan图像超分辨率
    Kubernetes IPVS和IPTABLES
    ts面试题总结
    ubuntu20.04挂载拓展盘保姆级流程
    力扣vip
  • 原文地址:https://blog.csdn.net/Jason6620/article/details/128028114