找了网上的博客,照着做了,发现其中有不少坑,特此记录,与君共勉。
传送门
1 在新建qt widget application 之后,开始进入正式内容
2 新建c++类,类名为OpenGLWidget,基类为QOpenGLWidget,勾选Include QWidget
3 编辑OpenGLWidget类,代码如下
openglwidget.h
#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H
#include
#include
#include
#include
class OpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
OpenGLWidget();
protected:
void initializeGL();
void paintGL();
void resizeGL(int w, int h);
void initVbo();
private:
GLint matrixLocation;
GLint vertexLocation;
GLint colorLocation;
GLint programId;
int vVerticesLen;
int triIndexLen;
int colorsLen;
GLuint verVbo;
GLuint indexVbo;
GLuint colorVbo;
QOpenGLShaderProgram* program;
GLfloat* vertex;
GLuint* triIndexs;
GLfloat* colors;
//GL_FLOAT_MAT4 projection;
QMatrix4x4 projection;
};
#endif // OPENGLWIDGET_H
openglwidget.cpp
#include "openglwidget.h"
OpenGLWidget::OpenGLWidget()
{
}
void OpenGLWidget::initializeGL()
{
//调用内容初始化函数
initializeOpenGLFunctions();
//三角形顶点坐标
vertex = new GLfloat[6]{
-0.5f,0,
0.5f,0,
0,0.5f
};
//三角形顶点索引
triIndexs =new GLuint[3] {0, 1, 2};
//三角形顶点颜色
colors= new GLfloat[12]{1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
program = new QOpenGLShaderProgram(this);
if(!program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader/fragmentShader.frag")){
return;
}
if(!program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader/vertexShader.vert")){
return;
}
if(!program->link()){
return;
}
if(!program->bind()){
return;
}
// 获取shaderprogram的id号,然后可以通过id号获取一些属性...
programId = program->programId();
// 从shaderprogram里面获取变量标识
matrixLocation = glGetUniformLocation(programId, "matrix");
vertexLocation = glGetAttribLocation(programId, "vPosition");
colorLocation = glGetAttribLocation(programId, "vColor");
initVbo();
}
void OpenGLWidget::initVbo(){
// 计算获得数组长度
//vVerticesLen = sizeof(vertex)/sizeof(GLfloat);
//triIndexLen = sizeof(triIndexs)/sizeof(GLuint);
// colorsLen = sizeof(colors)/sizeof(GLfloat);
vVerticesLen = 6;
triIndexLen = 3;
colorsLen = 12;
qDebug() << vVerticesLen << " " << triIndexLen << " " << colorsLen;
// 初始化顶点buffer并装载数据到显存
glGenBuffers(1, &verVbo);
glBindBuffer(GL_ARRAY_BUFFER, verVbo);
glBufferData(GL_ARRAY_BUFFER, vVerticesLen * sizeof(GLfloat), vertex, GL_STATIC_DRAW);
// 初始化索引buffer并装载数据到显存
glGenBuffers(1, &indexVbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triIndexLen * sizeof(GLuint), triIndexs, GL_STATIC_DRAW);
// 初始化颜色buffer并装载数据到显存
glGenBuffers(1, &colorVbo);
glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
glBufferData(GL_ARRAY_BUFFER, colorsLen * sizeof(GLfloat), colors, GL_STATIC_DRAW);
}
void OpenGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// shader传入模型视图矩阵 projection可以理解为建立了一个坐标系空间,可以再这个空间内设置图形
glUniformMatrix4fv(matrixLocation, 1, GL_FALSE, projection.data());
// shader绑定并启用颜色数组buffer
glBindBuffer(GL_ARRAY_BUFFER,colorVbo);
glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(colorLocation);
// 颜色值rgba,所以每四个float值作为一个颜色值,如果只是希望rgb,取三个值作为颜色值即可!
// shader绑定并启用顶点数组buffer
glBindBuffer(GL_ARRAY_BUFFER, verVbo);
glVertexAttribPointer( vertexLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(vertexLocation);
// shader绑定并顶点索引数组buffer - 索引无需启用
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,indexVbo);
glDrawElements(GL_TRIANGLES, triIndexLen, GL_UNSIGNED_INT,0);
// 解绑buffer、关闭启用顶点、颜色数组
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(vertexLocation);
glDisableVertexAttribArray(colorLocation);
}
void OpenGLWidget::resizeGL(int w, int h)
{
//当窗口大小改变时,调整界面坐标显示高度和宽度
glViewport(0, 0, w, h);
// 模型矩阵重置
projection.setToIdentity();
// 透视投影
// qreal aspect = qreal(w) / qreal(h ? h : 1);
// projection.perspective(60.0f, aspect, 1.0f, 100.0f);
// 增加了模型矩阵,需要做一定偏移量,保证物体刚开始渲染出来时可以被看到!
// projection.translate(0.0f, 0.0f, -2.0f);
}
4 在MainWindow的构造函数中新建OpenGLWidget对象,并插入ui中,代码如下
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "openglwidget.h"
#include "QVBoxLayout"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
OpenGLWidget* openGLWidget = new OpenGLWidget();
//为了便于让OpenGLWidget自动填充父窗口,这里为父窗口设置了一个布局
QVBoxLayout* centralLayout = new QVBoxLayout();
centralLayout->addWidget(openGLWidget);
this->ui->centralWidget->setLayout(centralLayout);
}
MainWindow::~MainWindow()
{
delete ui;
}
5 这里会用到两个shader文件,一个是顶点shader vertexShader.vert ,一个是片元shader fragmentShader.frag。
代码如下:
vertexShader.vert
#version 330 core
uniform mat4 matrix;
in vec4 vPosition;
in vec4 vColor;
out vec4 fColor;
void main(void)
{
fColor = vColor;
gl_Position = matrix * vPosition;
}
fragmentShader.frag
#version 330 core
in vec4 fColor;
out vec4 fragColor;
void main(void)
{
//gl_FragColor = fColor;
fragColor = vec4(1,0,0,1);
}
6 我之前是直接在qt中新建glsl文件,然后它的默认位置是与pro文件同一目录下,然后使用”vertexShader.vert”,会报错:unable to open file “vertexShader.vert”。
之后再各种搜索之后发现别人给出的建议是,采用资源文件的方式来访问这两个shader文件,不会出错。
具体的步骤就是:
在qt中新建资源文件,然后添加前缀,添加文件的方式,将这两个文件添加到资源文件中。比如这里vertexShader.vert位于默认位置,那么先添加前缀 /shader,然后添加文件vertexShader.vert。这样就可以使用路径 “:/shader/vertexShader.vert” 来访问该文件了