Qt+OpenGL——通过索引绘制管道模型并使用鼠标控制摄像机镜头

最终效果
在这里插入图片描述

头文件

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QOpenGLShaderProgram>

#include "glcamera.h"

class GLWidget : public QOpenGLWidget,public QOpenGLFunctions_4_5_Core
{
    Q_OBJECT
public:
    explicit GLWidget(QWidget *parent=nullptr);
    ~GLWidget();

protected:

    void iniDatas();

    void initializeGL(); //初始化相关的操作全在这个函数中完成
    void resizeGL(int w,int h);
    void paintGL();

    float *getCylinderVertex(int segment, float r1, float r2, int &count);
    int *getCylinderIndices(int segment, int &count);

    void wheelEvent(QWheelEvent *pEvent);

    void mousePressEvent(QMouseEvent *pEvent);
    void mouseMoveEvent(QMouseEvent *pEvent);
    void mouseReleaseEvent(QMouseEvent *pEvent);
private:
    QOpenGLShaderProgram *m_pShaderProgram = nullptr;
    GLCamera *m_pCamera = nullptr;

    QMatrix4x4 m_mat4Model;
    QPoint m_pointMouseDown;

    Qt::MouseButton m_mouseBtn;

    int m_nDataCount = 0;

};

#endif // GLWIDGET_H

#include "glwidget.h"
#include <QOpenGLBuffer>
#include <QtMath>

#include <QDebug>


#define BUFFER_OFFSET(offset) ((void*)(offset))


#define BALL_X_SEGMENT 40
#define BALL_Y_SEGMENT 50


GLuint VAO = -1;
GLWidget::GLWidget(QWidget *parent):
    QOpenGLWidget(parent)
{

}

GLWidget::~GLWidget()
{

}

void GLWidget::iniDatas()
{
    int nIndicesCount = 0;
    int nDataCount = 0;
    float *vertices = getCylinderVertex(BALL_X_SEGMENT,0.6f,0.8f,nDataCount);
    int *indices = getCylinderIndices(BALL_X_SEGMENT,nIndicesCount);

    glGenVertexArrays(1,&VAO);
    glBindVertexArray(VAO);

    GLuint VBO;
    glGenBuffers(1,&VBO);
    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(vertices) * nDataCount,
                 vertices,GL_STATIC_DRAW);
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(float) * 3,BUFFER_OFFSET(0));
    glEnableVertexAttribArray(0);

    GLuint EBO;
    glGenBuffers(1,&EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices) * nIndicesCount,indices,GL_STATIC_DRAW);

    glBindVertexArray(0);//解绑
    glBindBuffer(GL_ARRAY_BUFFER,0);

    m_nDataCount = nIndicesCount;

    //        glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);//填充图
    //            glPolygonMode(GL_FRONT_AND_BACK,GL_POINT);//散点图
    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);//线框图
}

void GLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    m_pShaderProgram = new QOpenGLShaderProgram(this);
    m_pShaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex,":/shaders/vertext.vert");
    m_pShaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment,":/shaders/fragment.frag");
    m_pShaderProgram->link();
    m_pShaderProgram->bind();

    m_pCamera = new GLCamera(this->width() * 1.0/this->height());
    iniDatas();
}

void GLWidget::resizeGL(int w, int h)
{
    glViewport(0,0,w,h);
}

void GLWidget::paintGL()
{
    static const GLfloat color[] = {0.0f,0.0f,0.0f,1.0f};

    glClearBufferfv(GL_COLOR,0,color);

    if(VAO == -1){
        return;
    }

    m_pShaderProgram->setUniformValue("model",m_mat4Model);
    m_pShaderProgram->setUniformValue("view",m_pCamera->getCameraMatrix());

    glUseProgram(m_pShaderProgram->programId());
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES,m_nDataCount,GL_UNSIGNED_INT,0);

    glBindVertexArray(0);

    update();
}


float *GLWidget::getCylinderVertex(int segment, float r1, float r2,int &count)
{
    float alpha = 2 * M_PI / segment;

    count = (segment + 1) * 3 * 4;
    float *data = new float[count];

    int a = 2;
    int b = 1;
    int c = 0;

    int nIndex = 0;
    for (int i = 0; i <= segment; ++i) {
        data[nIndex + a] = r1 * qSin(alpha * i);
        data[nIndex + b] = r1 * qCos(alpha * i);
        data[nIndex + c] = -r2;
        nIndex += 3;

    }

    for (int i = 0; i <= segment; ++i) {
        data[nIndex + a] = r2 * qSin(alpha * i);
        data[nIndex + b] = r2 * qCos(alpha * i);
        data[nIndex + c] = -r2;
        nIndex += 3;
    }

    for (int i = 0; i <= segment; ++i) {
        data[nIndex + a] = r1 * qSin(alpha * i);
        data[nIndex + b] = r1 * qCos(alpha * i);
        data[nIndex + c] = r2;
        nIndex += 3;

    }

    for (int i = 0; i <= segment; ++i) {
        data[nIndex + a] = r2 * qSin(alpha * i);
        data[nIndex + b] = r2 * qCos(alpha * i);
        data[nIndex + c] = r2;
        nIndex += 3;
    }


    return data;
}

int *GLWidget::getCylinderIndices(int segment,int &count)
{
    count = segment * 6 * 4;
    int *indices = new int[count];

    int nIndex = 0;
    //第一个圆环
    for (int i = 0; i < segment; ++i) {
        indices[nIndex] = i;
        indices[nIndex + 1] = segment + (i + 1);
        indices[nIndex + 2] = i + 1;
        indices[nIndex + 3] = i + 1;
        indices[nIndex + 4] = segment + (i + 1);
        indices[nIndex + 5] = segment + (i + 2);

        nIndex += 6;
    }

    //第一层形成柱 0,2
    for (int i = 0; i < segment; ++i) {
        indices[nIndex] = i;
        indices[nIndex + 1] = segment * 2 + i + 2;
        indices[nIndex + 2] = i + 1;
        indices[nIndex + 3] = i + 1;
        indices[nIndex + 4] = segment * 2 + (i + 2);
        indices[nIndex + 5] = segment * 2 + (i + 3);

        nIndex += 6;
    }


    //第二个圆环
    for (int i = 0; i < segment; ++i) {
        indices[nIndex] = i + (segment * 2 + 2);
        indices[nIndex + 1] = segment * 3 + (i + 3);
        indices[nIndex + 2] = i + 1 + (segment * 2 + 2);
        indices[nIndex + 3] = i + 1 + (segment * 2 + 2);
        indices[nIndex + 4] = segment * 3 + (i + 3);
        indices[nIndex + 5] = segment * 3 + (i + 4);

        nIndex += 6;
    }


    //第二层形成柱 1,3
    for (int i = 0; i < segment; ++i) {
        indices[nIndex] = i + segment + 1;
        indices[nIndex + 1] = segment * 3 + (i + 3);
        indices[nIndex + 2] = i + 1 + segment + 1;
        indices[nIndex + 3] = i + 1 + segment + 1;
        indices[nIndex + 4] = segment * 3 + (i + 3);
        indices[nIndex + 5] = segment * 3 + (i + 4);
        nIndex += 6;
    }

    return indices;
}

void GLWidget::wheelEvent(QWheelEvent *pEvent)
{
    if(!m_pCamera){
        return;
    }

    if(pEvent->delta() > 0){//向上滚动,放大
        m_pCamera->adjustFocus(1.2f);
    }else{
        m_pCamera->adjustFocus(1/1.2f);
    }

    update();
    QOpenGLWidget::wheelEvent(pEvent);
}

void GLWidget::mousePressEvent(QMouseEvent *pEvent)
{
    m_pointMouseDown = pEvent->pos();
    m_mouseBtn = pEvent->button();
}

void GLWidget::mouseMoveEvent(QMouseEvent *pEvent)
{
    QPoint pos = pEvent->pos();
    QVector2D offset(pos.x() - m_pointMouseDown.x(),
                     pos.y() - m_pointMouseDown.y());

    m_pointMouseDown = pos;

    if(m_mouseBtn == Qt::LeftButton){
        int angleX = offset.x() / width() * 180;
        int angleY = offset.y() / width() * 90;

        m_pCamera->rotate(angleX,angleY);
    }else{
        m_pCamera->translate(-offset.x() / this->width() * 5,-offset.y() / this->height() * 5);
    }

}

void GLWidget::mouseReleaseEvent(QMouseEvent *pEvent)
{
    m_pointMouseDown = pEvent->pos();
    m_mouseBtn = Qt::NoButton;
}

shader文件

#version 450 core

layout(location=0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
void main()
{
        gl_Position = view * model * vec4(aPos,1);
}

已标记关键词 清除标记
相关推荐
<p> <span>要想成为高级程序员,<span>必须精通</span>C++。大量第三方开源库使用C++编写。开发移动应用的一些核心功能必须使用C C++。Qt是大公司大量使用的跨平台c++库,号称工具软件之王。Qt作为一个如此高效,跨平台的GUI开发框架,如何快速掌握其精髓?写出高质量,复杂的交互?这是困扰很多中高级开发人员,很头疼的一个问题。在这个课程中,我们会给出非常好的答案。<br /> </span> </p> <p> <span>为什么很多同学学了很多年编程,看了很多书,教程,还是不会写,只能在网络上copy代码?或者自己没有动手能力,遇到稍微复杂的东西就束手无策?为什么那些高效率学习的人,能在三五天内掌握Qt,并开始写软件,做项目?一个类似Qt这样的开发框架,几千个API,如何学习?为什么我们同学学习了一两年Qt C++还糊里糊涂,有的人只需要几天时间就掌握Qt的精髓?<br /> 通过这个系列课程的学习,让学员深入理解一套GUI开发框架,编程思想。并将这套思想应用到任何平台的开发中,例如iOS,Android。 </span> </p> <p> <span>理解这套编程思想,日后可以运用于快速学习任何一套新的东西,框架。</span> </p> 通过这一系列课程的训练,希望大家能达到无招胜有招的境界。达到以后遇到任何客户端软件,拍着胸脯说,我闭着眼睛都能写出来的境界。<br /> <br /> <br /> <br /> <br />
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:白松林 返回首页