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的效果。