Qt6.9 QtOpenGL绘制3D球体demo

pro文件:
QT       += core gui opengl openglwidgets widgets

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp \
    openglwidget.cpp

HEADERS += \
    mainwindow.h \
    openglwidget.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
spherewidget.h

// spherewidget.h
#ifndef SPHEREWIDGET_H
#define SPHEREWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QMatrix4x4>

class SphereWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    explicit SphereWidget(QWidget *parent = nullptr);
    ~SphereWidget();

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

private:
    void createSphere(float radius, int sectors, int stacks);

    QOpenGLShaderProgram *m_program;
    QOpenGLBuffer m_vbo;
    QOpenGLVertexArrayObject m_vao;
    QMatrix4x4 m_projection;

    int m_numVertices;
    float m_angle;
};

#endif // SPHEREWIDGET_H
spherewidget.cpp

// spherewidget.cpp
#include "openglwidget.h"
#include <QDebug>
#include <cmath>

SphereWidget::SphereWidget(QWidget *parent)
    : QOpenGLWidget(parent)
    , m_program(nullptr)
    , m_vbo(QOpenGLBuffer::VertexBuffer)
    , m_numVertices(0)
    ,m_angle(0.0f)
{
}

SphereWidget::~SphereWidget()
{
    makeCurrent();
    m_vbo.destroy();
    m_vao.destroy();
    delete m_program;
    doneCurrent();
}

void SphereWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
    glEnable(GL_DEPTH_TEST);

    // 在initializeGL()中
    m_program = new QOpenGLShaderProgram(this);
    if(!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
                                            "#version 150\n"
                                            "in vec3 position;\n"
                                            "in vec3 color;\n"
                                            "uniform mat4 mvp;\n"
                                            "out vec3 vColor;\n"
                                            "void main() {\n"
                                            "   gl_Position = mvp * vec4(position, 1.0);\n"
                                            "   vColor = color;\n"
                                            "}\n")) {
        qDebug() << "Vertex shader error:" << m_program->log();
    }
    else
    {
        qDebug()<<"initializeGL()::first";
    }

    if(!m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
                                            "#version 150\n"
                                            "in vec3 vColor;\n"
                                            "out vec4 fragColor;\n"
                                            "void main() {\n"
                                            "   fragColor = vec4(vColor, 1.0);\n"
                                            "}\n")) {
        qDebug() << "Fragment shader error:" << m_program->log();
    }
    else
    {
        qDebug()<<"initializeGL()::first";
    }
    if(!m_program->link()) {
        qDebug() << "Shader link error:" << m_program->log();
    }
    else
    {
        qDebug()<<"initializeGL()::third";
    }
    // // 设置VAO和VBO
    m_vao.create();
    m_vao.bind();

    m_vbo.create();
    m_vbo.bind();
    // // 创建球体几何体
    createSphere(1.0f, 36, 18);


    // 绑定属性位置
    m_program->bindAttributeLocation("position", 0);
    m_program->bindAttributeLocation("color", 1);

    m_program->bind();
    m_program->enableAttributeArray(0); // position
    m_program->setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(GLfloat));
    m_program->enableAttributeArray(1); // color
    m_program->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(GLfloat), 3, 6 * sizeof(GLfloat));
    m_program->release();

    // initializeOpenGLFunctions();
    // glClearColor(0.1f, 0.1f, 0.2f, 1.0f);
    // glEnable(GL_DEPTH_TEST);

    // // 创建着色器程序
    // m_program = new QOpenGLShaderProgram(this);
    // m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
    //                                    "#version 150 core\n"
    //                                    "layout(location = 0) in vec3 position;\n"
    //                                    "layout(location = 1) in vec3 color;\n"
    //                                    "uniform mat4 mvp;\n"
    //                                    "out vec3 vColor;\n"
    //                                    "void main() {\n"
    //                                    "   gl_Position = mvp * vec4(position, 1.0);\n"
    //                                    "   vColor = color;\n"
    //                                    "}\n");
    // m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
    //                                    "#version 150 core\n"
    //                                    "in vec3 vColor;\n"
    //                                    "out vec4 fragColor;\n"
    //                                    "void main() {\n"
    //                                    "   fragColor = vec4(vColor, 1.0);\n"
    //                                    "}\n");
    // m_program->link();


    // // 设置顶点属性
    // m_program->enableAttributeArray(0);
    // m_program->setAttributeBuffer(0, GL_FLOAT, 0, 3, 6 * sizeof(GLfloat));
    // m_program->enableAttributeArray(1);
    // m_program->setAttributeBuffer(1, GL_FLOAT, 3 * sizeof(GLfloat), 3, 6 * sizeof(GLfloat));
}

void SphereWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
    m_projection.setToIdentity();
    m_projection.perspective(45.0f, GLfloat(w) / h, 0.01f, 100.0f);
}

void SphereWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    m_program->bind();

    QMatrix4x4 modelView;
    modelView.translate(0.0f, 0.0f, -5.0f);  // 将相机向后移动
    modelView.rotate(m_angle, 0.0f, 1.0f, 0.0f); // Y轴旋转

    QMatrix4x4 mvp = m_projection * modelView;
    m_program->setUniformValue("mvp", mvp);

    glDrawArrays(GL_TRIANGLES, 0, m_numVertices);

    m_program->release();

    m_angle += 0.5f;
    update();
}

void SphereWidget::createSphere(float radius, int sectors, int stacks)
{
    const float PI = 3.14159265358979323846f;
    float x, y, z, xy;
    float nx, ny, nz, lengthInv = 1.0f / radius;
    //float s, t;

    float sectorStep = 2 * PI / sectors;
    float stackStep = PI / stacks;
    float sectorAngle, stackAngle;

    std::vector<GLfloat> vertices;

    for (int i = 0; i <= stacks; ++i) {
        stackAngle = PI / 2 - i * stackStep;
        xy = radius * cosf(stackAngle);
        z = radius * sinf(stackAngle);

        for (int j = 0; j <= sectors; ++j) {
            sectorAngle = j * sectorStep;

            x = xy * cosf(sectorAngle);
            y = xy * sinf(sectorAngle);

            // 顶点位置
            vertices.push_back(x);
            vertices.push_back(y);
            vertices.push_back(z);

            // 顶点颜色 (基于法线)
            nx = x * lengthInv;
            ny = y * lengthInv;
            nz = z * lengthInv;
            vertices.push_back((nx + 1.0f) * 0.5f);
            vertices.push_back((ny + 1.0f) * 0.5f);
            vertices.push_back((nz + 1.0f) * 0.5f);
        }
    }

    std::vector<GLuint> indices;
    int k1, k2;
    for (int i = 0; i < stacks; ++i) {
        k1 = i * (sectors + 1);
        k2 = k1 + sectors + 1;

        for (int j = 0; j < sectors; ++j, ++k1, ++k2) {
            if (i != 0) {
                indices.push_back(k1);
                indices.push_back(k2);
                indices.push_back(k1 + 1);
            }

            if (i != (stacks - 1)) {
                indices.push_back(k1 + 1);
                indices.push_back(k2);
                indices.push_back(k2 + 1);
            }
        }
    }

    // 将索引转换为顶点数组
    std::vector<GLfloat> sphereVertices;
    for (size_t i = 0; i < indices.size(); ++i) {
        sphereVertices.push_back(vertices[indices[i] * 6]);
        sphereVertices.push_back(vertices[indices[i] * 6 + 1]);
        sphereVertices.push_back(vertices[indices[i] * 6 + 2]);
        sphereVertices.push_back(vertices[indices[i] * 6 + 3]);
        sphereVertices.push_back(vertices[indices[i] * 6 + 4]);
        sphereVertices.push_back(vertices[indices[i] * 6 + 5]);
    }

    m_numVertices = sphereVertices.size() / 6;
    m_vbo.allocate(sphereVertices.data(), sphereVertices.size() * sizeof(GLfloat));
}

运行效果边界上的细致感不如3D和Qt quick 3D的效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值