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);
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt、Assimp和OpenGL是三种常用的工具,在三维模型设计中发挥着重要的作用。Qt是一个跨平台的C++应用程序开发框架,它为用户提供了GUI和其他一些基本的用户界面组件。Assimp是一个允许用户读取和写入多种3D文件格式的库,包括OBJ、FBX、DAE等。OpenGL是一种用于创建高性能的计算机图形的API。因此,将这三种工具结合使用,可以方便地进行三维模型的开发。 在使用Qt、Assimp和OpenGL进行三维模型开发时,Qt主要负责提供GUI界面和基本的用户界面组件。Assimp则用于读取和写入不同格式的三维模型,然后通过OpenGL进行渲染展示。OpenGL作为一个底层API,提供了强大的图形处理能力,允许用户在计算机上创建复杂的3D场景和动。 具体地说,使用这三种工具进行三维模型开发的步骤通常如下:首先用Assimp读入各种格式的三维模型文件,然后通过OpenGL进行渲染显示。Qt可以用于创建一个GUI界面,方便用户进行模型读取、渲染、缩放、旋转、材质设定等基本的操作。同时,用户可以通过Qt的事件机制来和OpenGL进行交互:比如通过鼠标事件、键盘事件等,实现对三维模型的选择、移动等控制。在此基础上,用户还可以通过OpenGL的扩展和着色器功能等,使三维模型的渲染更加复杂和高效。 总之,Qt、Assimp和OpenGL是三种常用的工具,它们的结合使用可以让用户方便地进行三维模型的设计和开发。在实际应用中,用户可以根据实际需求选择不同的工具和技术,实现更加复杂和高效的三维模型

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值