Qt Opengl-widget-practice

这次我们将实践,实现一个线条。在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;
}

猜你喜欢

转载自blog.csdn.net/qq_39175540/article/details/85335515