Qt Opengl-widget-practice
阿新 • • 發佈:2019-01-11
這次我們將實踐,實現一個線條。在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;
}