这次我们将实践,实现一个线条。在z=0的平面绘制两条相交直线。
效果如下:
首先,我们做一个Ui,
class OpenglShow : public QOpenGLWidget,protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit OpenglShow(QWidget *parent = nullptr);
~OpenglShow(){}
void initializeGL();
void paintGL();
void resizeGL(int w, int h);
private:
// 投影矩阵 pMat
QMatrix4x4 m_projectMat;
// viewMat
QMatrix4x4 m_viewMat;
// renderItem
Line *m_lineItem;
};
void OpenglShow::initializeGL()
{
// opengl方法
initializeOpenGLFunctions();
// 深度测试开启
glEnable(GL_DEPTH_TEST);
// 视图矩阵单位一
m_viewMat.setToIdentity();
// 从z轴正1的位置朝向原点,头的朝向为y轴正方向
m_viewMat.lookAt(QVector3D(0,0,2), QVector3D(0,0,0), QVector3D(0,1,0));
// renderItem
m_lineItem = new Line(this);
}
void OpenglShow::paintGL()
{
glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QVector<QVector3D> data;
data.push_back(QVector3D(-1,0,0));
data.push_back(QVector3D(1,0,0));
m_lineItem->updataBuffer(data);
m_lineItem->render(m_projectMat * m_viewMat);
data[0].setY(0.5);
data[1].setY(-0.5);
m_lineItem->updataBuffer(data);
m_lineItem->render(m_projectMat * m_viewMat);
}
void OpenglShow::resizeGL(int w, int h)
{
// 视口即全屏
glViewport(0, 0, w, h);
// 投影矩阵单位一
m_projectMat.setToIdentity();
// 透视投影 眼角 宽高比 近平面 远平面 确定视锥体
m_projectMat.perspective(90.0f, (GLfloat)w/(GLfloat)h, 0.1f, 1000.0f);
}
线条实现:
class Line: public BaseRender
{
//.....
private:
QVector3D m_startVec;
QVector3D m_endVec;
}
Line::Line(QObject *parent)
:BaseRender (parent)
{
m_startVec = QVector3D(0, -1, 1);
m_endVec = QVector3D(0, 1, -1);
vertexVec.push_back(m_startVec);
vertexVec.push_back(m_endVec);
initBuffer();
initShader();
}
Line::~Line()
{}
void Line::render(QMatrix4x4 vpmat)
{
// render前数据绑定
m_buffer.bind();
m_shaderPro->bind();
// 启用属性ID为0的,即顶点坐标
m_shaderPro->enableAttributeArray(0);
// 顶点坐标传值
m_shaderPro->setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(QVector3D));
// 自身modelMat
QMatrix4x4 modelMat;
modelMat.setToIdentity();
// 告知着色器mvp矩阵和颜色
m_shaderPro->setUniformValue("qt_ModelViewProjectionMatrix",vpmat * modelMat);
m_shaderPro->setUniformValue("qt_color",QVector4D(0, 0, 0.7, 0.6));
// 开始draw
glDrawArrays(GL_LINES, 0, vertexVec.length());
// 解绑
m_shaderPro->release();
m_buffer.release();
}
void Line::updataBuffer(QVector<QVector3D> lineVecs)
{
vertexVec[0] = lineVecs.at(0);
vertexVec[1] = lineVecs.at(1);
m_buffer.bind();
// glBufferSubData(off ,data, count) 等效于write
m_buffer.write(0,vertexVec.constData(), sizeof(QVector3D)*2);
m_buffer.release();
}
void Line::initVertex()
{
}
void Line::initBuffer()
{
// 顶点数据初始化
initVertex();
// buffer设置为DynamicDraw buffer can be modified more times
m_buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
// buffer的创建,绑定,申请内存,释放
m_buffer.create();
m_buffer.bind();
m_buffer.allocate(vertexVec.constData(), sizeof(QVector3D)*vertexVec.length());
m_buffer.release();
}
void Line::initShader()
{
// 着色器程序 创建,添加顶点和片元着色器,链接,编译,释放,和属性ID
m_shaderPro = new QOpenGLShaderProgram(this);
m_shaderPro->addShaderFromSourceFile(QOpenGLShader::Vertex,":/planes.vert");
m_shaderPro->addShaderFromSourceFile(QOpenGLShader::Fragment,":/planes.frag");
m_shaderPro->bindAttributeLocation("qt_Vertex",0);
m_shaderPro->link();
m_shaderPro->bind();
m_shaderPro->release();
}
顶点着色器,只使用了顶点坐标和mvp矩阵
// 着色器程序属性绑定 ID = 0
attribute vec4 qt_Vertex;
uniform mat4 qt_ModelViewProjectionMatrix;
void main(void)
{
gl_Position = qt_ModelViewProjectionMatrix * qt_Vertex;
}
片元着色器,仅指定颜色,常用来确认顶点坐标是否ok
uniform vec4 qt_color;
void main(void)
{
gl_FragColor = qt_color;
}