本帖将参考LearnOpenGL这一经典教程,使用Qt的原生环境完成教程中所提的所有流程,并尽量和原教程保持一致,如有错误,欢迎评论!
为了方便大家参考,我将项目分享至了gitee,并实时进行更行:Qt实现OpenGL的经典教程: (gitee.com)
Qt版本:6.7
操作系统:Windows10
进入3D
为了真正地进入3D空间,我们分别实现projection ,view ,model矩阵,其中model负责将模型转换为世界坐标,view则是摄像机变换,projection则是透视变换。我们对上一篇博文结尾的顶点着色器做进一步修改:
#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);
}
这里分别左乘了model,view和projection三个矩阵,这一顺序不能变,因为矩阵的乘法没有交换律。
随后,我们对PaintGL中的代码进行修改:
void MyOpenGLWidget::paintGL()
{
//由于继承了QOpenGLFunctions,可以直接使用OpenGL中的函数
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// bind Texture
glActiveTexture(GL_TEXTURE0);
_texture->bind();
glActiveTexture(GL_TEXTURE1);
_texture1->bind();
QMatrix4x4 model;
QMatrix4x4 view;
QMatrix4x4 projection;
model.rotate(-55.0f, 1.0f, 0.0f, 0.0f);
view.translate(QVector3D(0.0f, 0.0f, -3.0f));
projection.perspective(45.0f,
float(this->width())/float(this->height()),
0.1f,
100.0f);
// update shader uniform
_shaderProgram->bind();
_shaderProgram->setUniformValue("model", model);
_shaderProgram->setUniformValue("view", view);
_shaderProgram->setUniformValue("projection", projection);
// render the triangle
_vao->bind();
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
我们分别创建model,view和projection的单位矩阵,然后让模型沿着x轴旋转-55°,将摄像机移动到z轴上-3的位置,并设置变换视角为透视视角,fov为45°,并将这三个矩阵分别赋值给顶点着色器中设置的uniform,点击运行:
为了提高效率,你也可以 将projection的赋值工作放到初始化阶段。
更加3D
我们开始用这个箱子面来画一个真正的立方体了!首先我们加载更多的顶点(36个顶点):
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
};
然后,我们修改PaintGL的绘制方式:
void MyOpenGLWidget::paintGL()
{
//由于继承了QOpenGLFunctions,可以直接使用OpenGL中的函数
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// bind Texture
glActiveTexture(GL_TEXTURE0);
_texture->bind();
glActiveTexture(GL_TEXTURE1);
_texture1->bind();
QMatrix4x4 model;
QMatrix4x4 view;
QMatrix4x4 projection;
model.rotate(qRadiansToDegrees(QTime::currentTime().msecsSinceStartOfDay()/1000.0f),
0.5f,
1.0f,
0.0f);
view.translate(QVector3D(0.0f, 0.0f, -3.0f));
projection.perspective(45.0f,
float(this->width())/float(this->height()),
0.1f,
100.0f);
// update shader uniform
_shaderProgram->bind();
_shaderProgram->setUniformValue("model", model);
_shaderProgram->setUniformValue("view", view);
_shaderProgram->setUniformValue("projection", projection);
// render the triangle
_vao->bind();
glDrawArrays(GL_TRIANGLES, 0, 36);
}
我们让正方体随时间旋转,同时修改绘制方式画36个点,点击运行,我们得到了一个奇怪的旋转正方体:
这是因为没有开启深度测试,我们开启深度测试:
glEnable(GL_DEPTH_TEST);
并在PaintGL中清除深度缓冲:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
再次点击运行,变一切正常了!
更多的立方体
为了创建更多的立方体,我们在MyOpenGLWidget类声明中定义更多的位置信息:
private:
QOpenGLShaderProgram *_shaderProgram;
QOpenGLTexture *_texture;
QOpenGLTexture *_texture1;
QOpenGLVertexArrayObject *_vao;
QOpenGLBuffer *_vbo;
QOpenGLBuffer *_ebo;
QList<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)
};
我们添加了一个_cubePositions来指示立方体位置,在渲染阶段我们修改model矩阵来在每一次调用中创建十个立方体:
void MyOpenGLWidget::paintGL()
{
//由于继承了QOpenGLFunctions,可以直接使用OpenGL中的函数
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除颜色和深度缓冲
// bind Texture
glActiveTexture(GL_TEXTURE0);
_texture->bind();
glActiveTexture(GL_TEXTURE1);
_texture1->bind();
QMatrix4x4 model;
QMatrix4x4 view;
QMatrix4x4 projection;
view.translate(QVector3D(0.0f, 0.0f, -3.0f));
projection.perspective(45.0f,
float(this->width())/float(this->height()),
0.1f,
100.0f);
// update shader uniform
_shaderProgram->bind();
_shaderProgram->setUniformValue("view", view);
_shaderProgram->setUniformValue("projection", projection);
// render the triangle
_vao->bind();
for(int i = 0; i < _cubePositions.size(); ++i){
model = QMatrix4x4();
model.translate(_cubePositions[i]);
model.rotate(20.0f * i, 1.0f, 0.3f, 0.5f);
_shaderProgram->setUniformValue("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
}
点击运行,我就得到了和LearnOpenGL中一样的结果了!