Qt绘制3D图形例程

本文主要内容是关于QOpenGLWidget的使用。此控件用于代替旧的QGLWidget类。关于此类的使用方法可以参考Qt帮助相关内容。

下面将从简到繁给出3个例子带读者入门Qt3D的世界。以下代码开发平台是VS2017和Qt5.9。

一、绘制曲面和颜色

本代码实现了一个沿着x轴旋转的彩色曲面。头文件:

class QOpenGLShaderProgram;

//---------------------------------------------------------------------------------------
// 显示彩虹色
//---------------------------------------------------------------------------------------
class MyOpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions
{
    Q_OBJECT

public:
    MyOpenGLWidget(QWidget* parent = 0);

private:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;

private:
    QOpenGLShaderProgram* program;
    int iter;
};

CPP文件:

MyOpenGLWidget::MyOpenGLWidget(QWidget* parent) :
    QOpenGLWidget(parent), iter(0)
{
    QSurfaceFormat surface;
    surface.setSamples(4);
    setFormat(surface);

    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, QOverload<>::of(&MyOpenGLWidget::update));
    timer->setInterval(100);
    timer->start();
}

void MyOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glEnable(GL_DEPTH_TEST);

    QOpenGLShader* vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
    const char* vsrc = R"(
        in vec4 vposition;
        in vec4 vcolor;
        out vec4 ocolor;
        uniform mat4 trans;
        void main() {
            gl_Position = trans * vposition;
            ocolor = vcolor;
        })";
    vshader->compileSourceCode(vsrc);
    QOpenGLShader* fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
    const char* fsrc = R"(
        in vec4 ocolor;
        void main() {
            gl_FragColor = ocolor;
        })";
    fshader->compileSourceCode(fsrc);

    program = new QOpenGLShaderProgram(this);
    program->addShader(vshader);
    program->addShader(fshader);
    program->link();
    program->bind();

    delete vshader;
    delete fshader;
}

void MyOpenGLWidget::paintGL()
{
    GLfloat vertices[] =
    {
        -0.8f, 0.8f, 0.2f,
        -0.8f, -0.8f, -0.3f,
        0.8f, 0.8f, 0.0f,
        0.8f, -0.8f, 0.5f,
    };
    GLfloat colors[] =
    {
        0.9f, 0.7f, 0.1f,
        0.2f, 0.7f, 0.3f,
        0.8f, 0.0f, 0.5f,
        0.1f, 0.1f, 0.9f,
    };
    
    QMatrix4x4 matrix;
    matrix.perspective(60.0f, 1.0f, 1.0f, 100.0f);
    matrix.translate(0, 0, -3);
    matrix.rotate(iter * 1.0f, 1, 0, 0);
    program->setUniformValue("trans", matrix);
    program->enableAttributeArray("trans");
    iter++;

    program->setAttributeArray("vposition", vertices, 3);
    program->enableAttributeArray("vposition");
    program->setAttributeArray("vcolor", colors, 3);
    program->enableAttributeArray("vcolor");
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

void MyOpenGLWidget::resizeGL(int w, int h)
{
}

程序运行效果如下图:

二、绘制曲面和贴图

本代码实现了一个沿着z轴旋转的曲面,曲面上贴了图片。头文件:

class QOpenGLTexture;

//---------------------------------------------------------------------------------------
// 显示图片
//---------------------------------------------------------------------------------------
class MzOpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions
{
    Q_OBJECT

public:
    MzOpenGLWidget(QWidget* parent = 0);

private:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;

private:
    QOpenGLShaderProgram* program;
    QOpenGLTexture *texture;
    int iter;
};

CPP文件。注意下方代码中的变量texture没有释放,你或可以在程序退出时释放它:

MzOpenGLWidget::MzOpenGLWidget(QWidget* parent) :
    QOpenGLWidget(parent), iter(0)
{
    QSurfaceFormat surface;
    surface.setSamples(4);
    setFormat(surface);

    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, QOverload<>::of(&MzOpenGLWidget::update));
    timer->setInterval(100);
    timer->start();
}

void MzOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glEnable(GL_DEPTH_TEST);

    program = new QOpenGLShaderProgram(this);
    const char* vsrc = R"(
        in vec4 pos;
        in vec2 itextCoor;
        out vec2 otextCoor;
        uniform mat4 trans;
        void main() {
            gl_Position = trans * pos;
            otextCoor = itextCoor;
        })";
    program->addShaderFromSourceCode(QOpenGLShader::Vertex, vsrc);
    const char* fsrc = R"(
        uniform sampler2D image;
        in vec2 otextCoor;
        void main() {
            gl_FragColor = texture2D(image, otextCoor);
        })";
    program->addShaderFromSourceCode(QOpenGLShader::Fragment, fsrc);

    texture = new QOpenGLTexture(QImage(u8"F:/Mr.Duu/ProjectM/QtTest/QtTest/1.bmp"));
    texture->setMinificationFilter(QOpenGLTexture::LinearMipMapNearest); /* 缩小图片插值方法 */
    texture->setMagnificationFilter(QOpenGLTexture::LinearMipMapLinear); /* 放大图片插值方法 */
    texture->setWrapMode(QOpenGLTexture::Repeat);

    program->link();
    program->bind();
}

void MzOpenGLWidget::paintGL()
{
    GLfloat vertices[] =
    {
        -0.8f, 0.8f, 0.2f, 
        -0.8f, -0.8f, -0.3f, 
        0.8f, 0.8f, 0.0f, 
        0.8f, -0.8f, 0.5f, 
    };
    GLfloat coors[] = /* 此数组和vertices数组一一对应 */
    {
        0.0f, 0.0f,
        0.0f, 2.2f, 
        2.2f, 0.0f,
        2.2f, 2.2f,
    };
    
    QMatrix4x4 matrix;
    matrix.perspective(60.0f, 1.0f, 1.0f, 100.0f);
    matrix.translate(0, 0, -3);
    matrix.rotate(iter * 1.0f, 0, 1, 0);
    program->setUniformValue("trans", matrix);
    program->enableAttributeArray("trans");
    iter++;

    program->setAttributeArray("pos", vertices, 3);
    program->enableAttributeArray("pos");
    program->setAttributeArray("itextCoor", coors, 2);
    program->enableAttributeArray("itextCoor");
    program->setUniformValue("image", 0);
    texture->bind(0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

void MzOpenGLWidget::resizeGL(int w, int h)
{
}

程序运行效果如下:

三、绘制立体图形和颜色

立体图形其实也是曲面,只不过首尾点相同把曲面连接成了封闭的图形。下面给出一个绘制三棱锥的例子。头文件:

class QOpenGLTexture;

//---------------------------------------------------------------------------------------
// 显示图片
//---------------------------------------------------------------------------------------
class MxOpenGLWidget : public QOpenGLWidget, private QOpenGLFunctions
{
    Q_OBJECT

public:
    MxOpenGLWidget(QWidget* parent = 0);

private:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;

private:
    QOpenGLShaderProgram* program;
    int iter;
};

CPP文件:

MxOpenGLWidget::MxOpenGLWidget(QWidget* parent) :
    QOpenGLWidget(parent), iter(0)
{
    QSurfaceFormat surface;
    surface.setSamples(4);
    setFormat(surface);

    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, QOverload<>::of(&MxOpenGLWidget::update));
    timer->setInterval(100);
    timer->start();
}

void MxOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glEnable(GL_DEPTH_TEST);

    program = new QOpenGLShaderProgram(this);
    const char* vsrc = R"(
        in vec4 pos;
        in vec4 itextCoor;
        out vec4 otextCoor;
        uniform mat4 trans;
        void main() {
            gl_Position = trans * pos;
            otextCoor = itextCoor;
        })";
    program->addShaderFromSourceCode(QOpenGLShader::Vertex, vsrc);
    const char* fsrc = R"(
        in vec4 otextCoor;
        void main() {
            gl_FragColor = otextCoor;
        })";
    program->addShaderFromSourceCode(QOpenGLShader::Fragment, fsrc);

    program->link();
    program->bind();
}

void MxOpenGLWidget::paintGL()
{
    GLfloat vertices[] =
    {
        -0.8f, -0.4f, 0.3f,
        0.8f, -0.4f, 0.3f,
        0.0f, 0.8f, 0.0f,
        0.0f, -0.4f, -0.5f,
        -0.8f, -0.4f, 0.3f,
        0.8f, -0.4f, 0.3f,
    };
    GLfloat colors[] =
    {
        0.0f, 0.0f, 1.0f,
        0.0f, 1.0f, 0.0f,
        1.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f,
        1.0f, 1.0f, 0.0f,
    };

    QMatrix4x4 matrix;
    matrix.perspective(60.0f, 1.0f, 1.0f, 100.0f);
    matrix.translate(0, 0, -2);
    matrix.rotate(iter * 1.0f, 0, 1, 0);
    program->setUniformValue("trans", matrix);
    program->enableAttributeArray("trans");
    iter++;

    program->setAttributeArray("pos", vertices, 3);
    program->enableAttributeArray("pos");
    program->setAttributeArray("itextCoor", colors, 3);
    program->enableAttributeArray("itextCoor");
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
}

void MxOpenGLWidget::resizeGL(int w, int h)
{
}

程序运行效果如下图:

 

posted @ 2023-09-01 17:48  兜尼完  阅读(1335)  评论(0编辑  收藏  举报