我是靠谱客的博主 疯狂蜗牛,这篇文章主要介绍8. 摄像机类实现,现在分享给大家,希望可以做个参考。

效果,按下wasdqr可以平移,鼠标拖动可以旋转,滑轮可以缩放

 照相机类头文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#pragma once #include <QVector3D> #include <QMatrix4x4> #include <QKeyEvent> enum Camera_Movement { FORWARD,//前 BACKWARD,//后 LEFT,//左 RIGHT,//右 UP,//上 DOWN//下 }; const float YAW = -90.0f; const float PITCH = 0.0f; const float SPEED = 1.0f; const float SENSITIVITY = 0.01f; const float ZOOM = 45.0f; class Camera { public: //相机位置,相机的上轴,yaw关于y轴的旋转向左向右看的程度,pitch关于x轴的旋转,向上向下看的俯仰角 Camera(QVector3D position = QVector3D(0.0f, 0.0f, 0.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH); ~Camera(); QMatrix4x4 getViewMatrix(); void processMouseMovement(float xoffset, float yoffset, bool constraintPitch = true); void processMouseScroll(float yoffset); void processInput(float dt); QVector3D position;//摄像机位置向量 QVector3D worldUp;//世界坐标的上轴 QVector3D front;//摄像机的方向向量,其实就是-position QVector3D up;//上向量 QVector3D right;//右向量 //俯仰角 float picth; //偏航角 float yaw; float movementSpeed;//鼠标速度 float mouseSensitivity;//鼠标灵敏度 float zoom;缩放 之前有一个函数projection.perspective定义了视角的缩放,在那边会用到 bool keys[1024]; private: void updateCameraVectors(); void processKeyboard(Camera_Movement direction, float deltaTime); };

照相机类源文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "Camera.h" #include <QDebug> //传参 Camera::Camera(QVector3D position, QVector3D up, float yaw, float pitch) : position(position), worldUp(up), front(-position), picth(pitch), yaw(yaw), movementSpeed(SPEED), mouseSensitivity(SENSITIVITY), zoom(ZOOM) { this->updateCameraVectors(); for (uint i = 0; i != 1024; ++i) keys[i] = false; } Camera::~Camera() { } // Returns the view matrix calculated using Euler Angles and the LookAt Matrix QMatrix4x4 Camera::getViewMatrix() { QMatrix4x4 view; //(const QVector3D& eye, const QVector3D& center, const QVector3D& up); view.lookAt(this->position, this->position + this->front, this->up); return view; } //键盘按下事件 void Camera::processKeyboard(Camera_Movement direction, float deltaTime) { float velocity = this->movementSpeed * deltaTime;//速度 if (direction == FORWARD) this->position += this->front * velocity; if (direction == BACKWARD) this->position -= this->front * velocity; if (direction == LEFT) this->position -= this->right * velocity; if (direction == RIGHT) this->position += this->right * velocity; if (direction == UP) this->position += this->worldUp * velocity; if (direction == DOWN) this->position -= this->worldUp * velocity; } //鼠标移动事件 void Camera::processMouseMovement(float xoffset, float yoffset, bool constraintPitch) { xoffset *= this->mouseSensitivity; yoffset *= this->mouseSensitivity; this->yaw += xoffset; this->picth += yoffset; if (constraintPitch) { if (this->picth > 89.0f) this->picth = 89.0f; if (this->picth < -89.0f) this->picth = -89.0f; } this->updateCameraVectors(); } // 该参数表示竖直滚动大小,因为45时默认的视野值,所以把缩放级别限制在1到45 void Camera::processMouseScroll(float yoffset) { //小于45°时 if (this->zoom >= 1.0f && this->zoom <= 45.0f) this->zoom -= yoffset; if (this->zoom > 45.0f) this->zoom = 45.0f; if (this->zoom < 1.0f) this->zoom = 1.0f; } //按键移动 void Camera::processInput(float dt) { if (keys[Qt::Key_W]) processKeyboard(FORWARD, dt); if (keys[Qt::Key_S]) processKeyboard(BACKWARD, dt); if (keys[Qt::Key_A]) processKeyboard(LEFT, dt); if (keys[Qt::Key_D]) processKeyboard(RIGHT, dt); if (keys[Qt::Key_E]) processKeyboard(UP, dt); if (keys[Qt::Key_Q]) processKeyboard(DOWN, dt); } void Camera::updateCameraVectors() { 转动需要 // 通过俯仰角和偏航角得到新的xyz位置 QVector3D front; front.setX(cos(this->yaw) * cos(this->picth)); front.setY(sin(this->picth)); front.setZ(sin(this->yaw) * cos(this->picth)); this->front = front.normalized(); 移动需要 //利用世界上轴和相机向量叉乘获得右轴 //右轴等于上向量,鼠标向左的时候我们希望它向右移动,所以是front叉乘worldUp反之就反着叉乘 this->right = QVector3D::crossProduct(this->front, this->worldUp).normalized(); //同上 this->up = QVector3D::crossProduct(this->right, this->front).normalized(); }

 什么地方用到了照相机类

在构造函数中初始化其指针

在PaintGL函数中

 在事件重载的函数中

OpenGL类头文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#pragma once #include <QOpenGLWidget> #include <QOpenGLShaderProgram> #include <QOpenGLFunctions> #include <QOpenGLVertexArrayObject> #include <QOpenGLBuffer> #include <QOpenGLTexture> #include "Camera.h" class QtFunctionWidget : public QOpenGLWidget, protected QOpenGLFunctions { public: QtFunctionWidget(QWidget *parent = nullptr); ~QtFunctionWidget() Q_DECL_OVERRIDE; protected: virtual void initializeGL() Q_DECL_OVERRIDE; virtual void resizeGL(int w, int h) Q_DECL_OVERRIDE; virtual void paintGL() Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void keyReleaseEvent(QKeyEvent *event) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; private: QOpenGLShaderProgram shaderProgram; QOpenGLBuffer vbo; QOpenGLVertexArrayObject vao; QOpenGLTexture *texture1 = nullptr; QOpenGLTexture *texture2 = nullptr; QTimer* m_pTimer = nullptr; int m_nTimeValue = 0; // camera std::unique_ptr<Camera> camera;//相机指针 两个unique_ptr指针不能指向同一个对象,不能复制只能移动 bool m_bLeftPressed; QPoint m_lastPos;//上次的点 };

OpenGL类源文件

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#include "QtFunctionWidget.h" #include <QDebug> #include <QTimer> QtFunctionWidget::QtFunctionWidget(QWidget *parent) : QOpenGLWidget(parent), vbo(QOpenGLBuffer::VertexBuffer) { camera = std::make_unique<Camera>(QVector3D(5.0f, 0.0f, 10.0f));//创建并且返回unique_ptr对象 m_bLeftPressed = false; //重绘 m_pTimer = new QTimer(this); connect(m_pTimer, &QTimer::timeout, this, [=] { m_nTimeValue += 1; update(); }); m_pTimer->start(40); } QtFunctionWidget::~QtFunctionWidget() { //多线程调用保护 makeCurrent(); //glDeleteBuffers vbo.destroy(); //glDeleteVertexArrays vao.destroy(); delete texture1; delete texture2; //退出保护 doneCurrent(); } void QtFunctionWidget::initializeGL() { this->initializeOpenGLFunctions(); bool success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, "textures.vert"); if (!success) { qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log(); return; } success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, "textures.frag"); if (!success) { qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log(); return; } success = shaderProgram.link(); if (!success) { qDebug() << "shaderProgram link failed!" << shaderProgram.log(); } //VAO,VBO data 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 }; //绑定vao QOpenGLVertexArrayObject::Binder vaoBind(&vao); //创建vbo vbo.create(); //绑定vbo vbo.bind(); //分配数组内存空间 vbo.allocate(vertices, sizeof(vertices)); //和glVertexAttribPointer有区别 //glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) // void setAttributeBuffer(int location, GLenum type, int offset, int tupleSize, int stride = 0);//不需要填是否标准化 shaderProgram.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(GLfloat) * 5);//位置0,数据类型float,起始从0开始,元组大小为3个,步长为5个float shaderProgram.enableAttributeArray(0); shaderProgram.setAttributeBuffer(1, GL_FLOAT, sizeof(GLfloat) * 3, 2, sizeof(GLfloat) * 5); shaderProgram.enableAttributeArray(1); vbo.release();//vbo操作完毕,接下来就没有对vbo内存的操作了 //纹理一 texture1 = new QOpenGLTexture(QImage("container.jpg"), QOpenGLTexture::GenerateMipMaps); if (!texture1->isCreated()) { qDebug() << "Failed to load texture"; } //纹理的样式 texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat); texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat); texture1->setMinificationFilter(QOpenGLTexture::Linear); texture1->setMagnificationFilter(QOpenGLTexture::Linear); //纹理二 texture2 = new QOpenGLTexture(QImage("awesomeface.png").mirrored(true, true), QOpenGLTexture::GenerateMipMaps); if (!texture2->isCreated()) { qDebug() << "Failed to load texture"; } texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat); texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat); texture2->setMinificationFilter(QOpenGLTexture::Linear); texture2->setMagnificationFilter(QOpenGLTexture::Linear); // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) shaderProgram.bind();//纹理的值传递给着色器 shaderProgram.setUniformValue("texture1", 0);//0代表第一个纹理 shaderProgram.setUniformValue("texture2", 1);//1代表第二个纹理 glEnable(GL_DEPTH_TEST);//开启深度测试 } void QtFunctionWidget::resizeGL(int w, int h) { glViewport(0, 0, w, h); } //位置数组 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) }; void QtFunctionWidget::paintGL() { glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->processInput(1.0f);//本来参数是用来计算电脑两帧之间的时间的,这里用1代替 //绑定纹理 glActiveTexture(GL_TEXTURE0); texture1->bind(); glActiveTexture(GL_TEXTURE1); texture2->bind(); //想要着色器调用我们的c++程序就需要先bind shaderProgram.bind(); QMatrix4x4 projection; //perspective的第一个参数是缩放参数 projection.perspective(camera->zoom, 1.0f * width() / height(), 0.1f, 100.f); shaderProgram.setUniformValue("projection", projection); //通过照相机对象的内置函数获取视图数组 shaderProgram.setUniformValue("view", camera->getViewMatrix()); {//绑定vao QOpenGLVertexArrayObject::Binder vaoBind(&vao); for (unsigned int i = 0; i < 10; i++) { // 对每个物体都要计算model矩阵 QMatrix4x4 model; model.translate(cubePositions[i]);//平移 float angle = (i + 1.0f) * m_nTimeValue; model.rotate(angle, QVector3D(1.0f, 0.3f, 0.5f));//旋转 shaderProgram.setUniformValue("model", model);//把数据传递给着色器 glDrawArrays(GL_TRIANGLES, 0, 36); } } //解除绑定 texture1->release(); texture2->release(); shaderProgram.release(); } //键盘按下事件 //keys是一个bool的数组,通过以下两个函数来判断键盘是否按下 void QtFunctionWidget::keyPressEvent(QKeyEvent *event) { int key = event->key(); if (key >= 0 && key < 1024) camera->keys[key] = true; } void QtFunctionWidget::keyReleaseEvent(QKeyEvent *event) { int key = event->key(); if (key >= 0 && key < 1024) camera->keys[key] = false; } //鼠标是否按下事件 void QtFunctionWidget::mousePressEvent(QMouseEvent *event) { //按下该键把参数设置成true if (event->button() == Qt::LeftButton) { m_bLeftPressed = true; m_lastPos = event->pos(); } } //鼠标释放函数,把该值设置成false void QtFunctionWidget::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event);//Q_UNUSED() 没有实质性的作用,用来避免编译器警告 m_bLeftPressed = false; } //鼠标移动事件 void QtFunctionWidget::mouseMoveEvent(QMouseEvent *event) { //如果鼠标按下了就触发鼠标移动事件 if (m_bLeftPressed) { int xpos = event->pos().x(); int ypos = event->pos().y(); //x,y移动的距离 int xoffset = xpos - m_lastPos.x(); int yoffset = m_lastPos.y() - ypos;//qt的y坐标往下是正,opengl y坐标往上是正,openGL远点在中间,QT在左上角 //重置上一次的移动位置 m_lastPos = event->pos(); camera->processMouseMovement(xoffset, yoffset); } } //滚轮事件 void QtFunctionWidget::wheelEvent(QWheelEvent *event) { QPoint offset = event->angleDelta(); camera->processMouseScroll(offset.y() / 20.0f); }

顶点着色器

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#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.0f); TexCoord = aTexCoord; }

片段着色器

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
#version 330 core out vec4 FragColor; in vec2 TexCoord; uniform sampler2D texture1; uniform sampler2D texture2; void main() { FragColor = mix(texture2D(texture1, TexCoord), texture2D(texture2, TexCoord), 0.2f); }

最后

以上就是疯狂蜗牛最近收集整理的关于8. 摄像机类实现的全部内容,更多相关8.内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部