QT6.5+OpenGL绘制坐标轴,网格,纹理绘制2d文字,3d文字

通过这篇介绍,希望可以帮到大家更好的绘制3d图形 

QT6与OpenGL的结合

1. Qt 6提供了许多增强型模块,如Qt Quick 3D和Qt 3D,这些模块可以直接与OpenGL进行交互,使得在Qt 6中使用OpenGL进行图形渲染变得更加高效和便捷。

2. 要在Qt 6中使用OpenGL,首先需要在项目中包含相应的OpenGL库。 

pro文件加入:QT += charts opengl
win32: LIBS += -lOpenGL32
win32: LIBS += -lGLU32
unix: LIBS += -lglut -lGLU

 3. 在Qt 6中,可以通过多种方式对OpenGL渲染性能进行优化

4. 利用OpenGL的纹理管理,减少CPU到GPU的数据传输

5. 在Qt 6中,可以通过多种方式对OpenGL渲染性能进行优化

6. 操作简单

在QOpenGLWidget组件上渲染opengl:继承QOpenGLWidget和QOpenGLFunctions_4_5_Core
实现三个虚函数:initializeGL、resizeGL、paintGL

函数介绍 

glViewport: 重置当前的视口
glMatrixMode  选择投影矩阵
gluPerspective 建立透视投影矩阵,基于窗口宽度和高度
glTranslatef  平移
glRotatef 旋转
glPushMatrix 设置新的状态
gluProject 坐标转换;比如将三维坐标投影到屏幕,或者鼠标坐标转换为世界坐标等

 参考:https://learn.microsoft.com/zh-cn/windows/win32/opengl/glrecti

绘图介绍

  1. 绘制坐标系和网格
glPushMatrix();
    {
        glLineWidth(1.5);
        //沿x,y,z轴方向的平移, 平移到原点
        glTranslatef(m_translate.x, m_translate.y, m_translate.z);
        glBegin(GL_LINES); //绘制坐标轴
        {
            glEnable(GL_LINE_SMOOTH);
            //从原点绘制三条线
            glColor3f(1, 0, 0); glVertex3f(0, 0, 0); glVertex3f(m_Size.x, 0, 0); //X
            glColor3f(0, 1, 0); glVertex3f(0, 0, 0); glVertex3f(0, m_Size.y, 0); //Y
            glColor3f(0, 0, 1); glVertex3f(0, 0, 0); glVertex3f(0, 0, m_Size.z); //Z
        }
        glEnd();
        //绘制网格
        glColor3f(1, 1, 1);
        glLineWidth(1.0f);
        //绘制xy平面的网格, m_xyGridNum网格的横竖的数量
        paintXYGrid(m_xyGridNum[0], m_xyGridNum[1]);
        //绘制yz平面的网格, m_yzGridNum网格的横竖的数量
        paintYZGrid(m_yzGridNum[0], m_yzGridNum[1]);
    }
    glPopMatrix();


paintXYGrid:函数
    //计算分割成vNum数量,每一个网格的距离
    float xSpacing = m_Size.x / vNum;
    float ySpacing = m_Size.y / hNum;
    glBegin(GL_LINES);
    glEnable(GL_LINE_SMOOTH);
    for(int i = 1; i <= hNum; ++i)
    {
        float y = ySpacing * i;
        //绘制线
        glVertex3f(0, y, 0);
        glVertex3f(m_Size.x, y, 0);
    }
    for(int i = 1; i <= vNum; ++i)
    {
        float x = xSpacing * i;
        glVertex3f(x, 0, 0);
        glVertex3f(x, m_Size.y, 0);
    }
    glEnd();
paintYZGrid:函数
    float zSpacing = m_Size.z / vNum;
    float ySpacing = m_Size.y / hNum;
    glBegin(GL_LINES);
    glEnable(GL_LINE_SMOOTH);
    for(int i = 1; i <= hNum; ++i)
    {
        float y = ySpacing * i;

        glVertex3f(0, y, 0);
        glVertex3f(0, y, m_Size.z);
    }
    for(int i = 1; i <= vNum; ++i)
    {
        float z = zSpacing * i;
        glVertex3f(0, 0, z);
        glVertex3f(0, m_Size.y, z);
    }
    glEnd();

2. 坐标轴箭头
    // 坐标轴箭头
    GLUquadricObj *objCylinder = gluNewQuadric();
    glPushMatrix(); //X
    {
        glColor3f(1, 0, 0);
        //先平移到要绘制的三维坐标的点
        glTranslatef(m_translate.x + m_Size.x, m_translate.y, m_translate.z);
        glRotatef(90, 0, 1, 0); //按照y轴旋转90
        gluCylinder(objCylinder, 0.06, 0.0, 0.4, 50, 1);
    }
    glPopMatrix();

    glPushMatrix(); //Y
    {
        glColor3f(0, 1, 0);
        glTranslatef(m_translate.x, m_translate.y+m_Size.y, m_translate.z);
        glRotatef(-90, 1, 0, 0.0); // 沿着x轴转90度 使得y轴对着原z轴方向
        gluCylinder(objCylinder, 0.06, 0.0, 0.4, 50, 1);
    }
    glPopMatrix();

    glPushMatrix(); //Z
    {
        glColor3f(0, 0, 1);
        glTranslatef(m_translate.x, m_translate.y, m_translate.z+m_Size.z);
        gluCylinder(objCylinder, 0.06, 0.0, 0.4, 50, 1);
    }
    glPopMatrix();
3. 绘制3d文件

通过多条线绘制一个立体的文字

//生成文字绘制路径
    QPainterPath path;
    path.addText(QPointF((start.x+start.y+start.z)/2, 0),  QFont("Microsoft YaHei UI", 2), text);
    //转换成多边形列表
    QList<QPolygonF> poly = path.toSubpathPolygons();
    QList<QPolygonF>::iterator iter = poly.begin();
    glLineWidth(1);
    glColor3f(color.redF(), color.greenF(), color.blueF());
    while(iter != poly.end())
    {
        glBegin(GL_LINE_LOOP);
        {
            QPolygonF::iterator it = (*iter).begin();
            while(it != iter->end())
            {
                glVertex3f(start.x+0.02, start.y - it->ry() * 0.1, start.z - it->rx() * 0.1);
                it++;
            }
        }
        glEnd();
        iter++;
    }
4. 利用texture绘制2d文字

  两种方式:1. 通过图片加载到texture绘制文字

                    2. 通过文本生成QImage贴图到texture

  利用:QOpenGLShaderProgram和QOpenGLTexture绘制。QOpenGLShaderProgram是QT中用于管理OpenGL着色器程序的类;QOpenGLTexture来进行纹理操作。

工具类:

class CPaint2DTexture
{
public:
    CPaint2DTexture();
    virtual ~CPaint2DTexture();
    void createImage(QString& name, QFont &font, QColor& color);
    void createImage(QString& filePath);
    void resizeSize(int w, int h);
    void createTexture();
public:
    QOpenGLTexture* texture;
    QImage* img;
    int width;
    int height;
};

class CPaint2DTextTool
{
public:
    CPaint2DTextTool(int n, bool occlusion = true);
    virtual ~CPaint2DTextTool();
    void initShaderProgram();
    //通过文本绘制:index绘制在哪个texture;name绘制的文字;font字体;color颜色
    CPaint2DTexture* setText(int index, QString& name, QFont &font, QColor& color);
    //通过文件绘制:index绘制在哪个texture;filePath图片(png)路径
    CPaint2DTexture* setText(int index, QString& filePath);
    void resizeSize(int index, int w, int h);
    void createTextures();
    CPaint2DTexture* getTexture(int index);
    void getSize(int index, GLdouble* weight, GLdouble* height);
    /**
     * @brief drawTexture 真正绘制在窗口的函数
     * @param index  绘制texture
     * @param wx   表示绘制的x坐标
     * @param wy    表示y坐标
     * @param xOffset  x偏移值
     * @param yOffset  y偏移值
     * @return
     */
    bool drawTexture(int index, GLdouble wx, GLdouble wy, GLdouble xOffset, GLdouble yOffset);
    bool drawTexture(int index, GLdouble wx, GLdouble wy);
private:
    void draw(CPaint2DTexture* tmp, int wx, int wy);
private:
    int m_nums;
    bool m_occlusion;
    QOpenGLVertexArrayObject VAO;
    QOpenGLBuffer VBO;
    QOpenGLShaderProgram shaderProgram;
    CPaint2DTexture** textures;
};
CPaint2DTexture::CPaint2DTexture(){
    texture = NULL;
    img = NULL;
    width = 0;
    height = 0;
}
CPaint2DTexture::~CPaint2DTexture() {
    if (texture != NULL) {
        if(texture->isCreated())
            texture->destroy();
        delete texture;
        texture = NULL;
    }
    if (img != NULL) {
        delete img;
        img = NULL;
    }
}

void CPaint2DTexture::createImage(QString& name, QFont &font, QColor& color) {
    QFontMetrics fontMetrics(font);
    QRect bounding= fontMetrics.boundingRect(name);      //获取到字符串的外包矩形
    if (img != NULL) {
        delete img;
        img = NULL;
    }
    img = new QImage(bounding.size(),QImage::Format_ARGB32);
    img->fill(Qt::transparent);                        //使用透明色填充Image
    QPainter painter;
    painter.begin(img);
    painter.setRenderHints(QPainter::TextAntialiasing|QPainter::Antialiasing);  //开启抗锯齿
    painter.setFont(font);
    painter.setPen(color);
    painter.drawText(QRect(0,0,img->width(),img->height()),Qt::AlignCenter,name);
    painter.end();
    if (texture == NULL) {
        texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
    }
    width = img->width();
    height = img->height();
}
void CPaint2DTexture::createImage(QString& filePath) {
    img = new QImage(filePath);
    if (texture == NULL) {
        texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
    }
    width = img->width();
    height = img->height();
}
void CPaint2DTexture::resizeSize(int w, int h) {
    if (texture == NULL || img == NULL) {
        return;
    }
    int tw = img->width();
    int th = img->height();

    float ws = float(w) / float(tw);
    float hs = float(h) / float(th);

    if (ws > hs) {
        width = int(tw * hs);
        height = int(th * hs);
    }
    else{
        width = int(tw * ws);
        height = int(th * ws);
    }
}
void CPaint2DTexture::createTexture() {
    if (texture == NULL) {
        return;
    }
    if (texture->isCreated()) {
        return;
    }
    texture->create();
    texture->setData(img->mirrored());
}


//
CPaint2DTextTool::CPaint2DTextTool(int n, bool occlusion){
    m_nums = n;
    textures = new CPaint2DTexture*[m_nums];
    for(int i = 0; i < m_nums; i++) {
        textures[i] = NULL;
    }
    m_occlusion = occlusion;
}
void CPaint2DTextTool::initShaderProgram()
{
    VAO.create();
    QOpenGLVertexArrayObject::Binder bind(&VAO);
    VBO.create();
    VAO.bind();
    VBO.bind();
    static float vertex[]={
        //顶点            //纹理坐标
        -1.0f,-1.0f,    0.0f,0.0f,    //左下
        -1.0f, 1.0f,    0.0f,1.0f,    //左上
        1.0f,-1.0f,    1.0f,0.0f,    //右下
        1.0f, 1.0f,    1.0f,1.0f     //右上
    };
    VBO.allocate(vertex,sizeof (vertex));
    if (m_occlusion) {
        //vec4(pos,1,1) 控制 第二个值的范围来控制深度: 0 -1 0表示最前面; 1表示最小面
        shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,"#version 450 core\n"
                                                                    "attribute vec2 pos;\n"  //传入顶点位置
                                                                     "attribute vec2 texCoord;\n"  //颜色
                                                                     "varying vec2 outCoord;\n"  //传递给片段着色器
                                                                     "void main(void) {\n"
                                                                     "   gl_Position = vec4(pos,1,1);\n" //输出的位置
                                                                     "   outCoord = texCoord;\n"
                                                                     "}\n");
    }
    else {
        shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,"#version 450 core\n"
                                                                    "attribute vec2 pos;\n"
                                                                     "attribute vec2 texCoord;\n"
                                                                     "varying vec2 outCoord;\n"
                                                                     "void main(void) {\n"
                                                                     "   gl_Position = vec4(pos,0,1);\n"
                                                                     "   outCoord = texCoord;\n"
                                                                     "}\n");
    }

    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,
                                          "uniform sampler2D texture;\n"
                                          "varying vec2 outCoord;\n"
                                          "void main(void) {\n"
                                          "   gl_FragColor = texture2D(texture, outCoord);\n"  //取颜色
                                          "}\n");

    shaderProgram.link();
    shaderProgram.enableAttributeArray(0);
    shaderProgram.enableAttributeArray(1);
    shaderProgram.setAttributeBuffer(0,GL_FLOAT,0,               2,4*sizeof (float));
    shaderProgram.setAttributeBuffer(1,GL_FLOAT,2*sizeof (float),2,4*sizeof (float));
    VAO.release();
    VBO.release();
}

CPaint2DTexture* CPaint2DTextTool::setText(int index, QString& name, QFont &font, QColor& color) {
    if (name == "" || index >= m_nums) {
        return NULL;
    }
    if (textures[index] == NULL) {
        textures[index] = new CPaint2DTexture();
    }
    textures[index]->createImage(name, font, color);
    return textures[index];
}

CPaint2DTexture* CPaint2DTextTool::setText(int index, QString& filePath){
    if (filePath == "" || index >= m_nums) {
        return NULL;
    }
    QFile file(filePath);
    if(file.exists()) {
        if (textures[index] == NULL) {
            textures[index] = new CPaint2DTexture();
        }
        textures[index]->createImage(filePath);
    }
    return textures[index];
}

void CPaint2DTextTool::resizeSize(int index, int w, int h){
    if (index >= m_nums) {
        return;
    }
    if (textures[index] == NULL){
        return;
    }
    textures[index]->resizeSize(w, h);
}

void CPaint2DTextTool::createTextures() {
    for(int i = 0; i < m_nums; i++) {
        if (textures[i] != NULL) {
            textures[i]->createTexture();
        }
    }
}

CPaint2DTexture* CPaint2DTextTool::getTexture(int index){
    if (index >= m_nums) {
        return NULL;
    }
    return textures[index];
}

void CPaint2DTextTool::getSize(int index, GLdouble* weight, GLdouble* height){
    if (index >= m_nums) {
        return;
    }
    CPaint2DTexture* tmp = textures[index];
    if (tmp == NULL){
        return;
    }
    *weight = tmp->width;
    *height = tmp->height;
}

bool CPaint2DTextTool::drawTexture(int index, GLdouble wx, GLdouble wy,
                 GLdouble xOffset, GLdouble yOffset){
    if (index >= m_nums) {
        return false;
    }
    CPaint2DTexture* tmp = textures[index];
    if (tmp == NULL){
        return false;
    }
    wx = wx - tmp->width * 0.5 + xOffset;
    wy = wy - tmp->height * 0.5 + yOffset;
    draw(tmp, int(wx), int(wy));
    return true;
}

bool CPaint2DTextTool::drawTexture(int index, GLdouble wx, GLdouble wy){
    if (index >= m_nums) {
        return false;
    }
    CPaint2DTexture* tmp = textures[index];
    if (tmp == NULL){
        return false;
    }
    draw(tmp, int(wx), int(wy));
    return true;
}

CPaint2DTextTool::~CPaint2DTextTool() {
    for(int i = 0; i < m_nums; i++) {
        if (textures[i] != NULL)
        {
            delete textures[i];
            textures[i] = NULL;
        }
    }
    delete textures;
}

void CPaint2DTextTool::draw(CPaint2DTexture* tmp, int wx, int wy){
    glViewport(wx, wy, tmp->width, tmp->height);
    QOpenGLVertexArrayObject::Binder bind(&VAO);
    shaderProgram.bind();
    tmp->texture->bind(0);
    glDrawArrays(GL_TRIANGLE_STRIP,0,4);
    shaderProgram.release();
}

工程代码:opengl: QT 和 opengl

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值