QT opengl的使用cube

OpenGL能做的事情太多了!很多程序也看起来很复杂。很多人感觉OpenGL晦涩难懂,原因大多是被OpenGL里面各种语句搞得头大,一会gen一下,一会bind一下,一会又active一下。搞到最后都不知道自己在干嘛,更有可能因为某一步的顺序错误导致最后渲染出错,又或者觉得记下这些操作的顺序是非常烦人的一件事。那么,OpenGL为什么会长成这个样子呢?这篇文章旨在通过一个最简单的OpenGL程序开始,让我们能够“看懂”它,“记住”这些操作顺序。
我们先来解释一下OpenGL为什么会涉及这么多操作顺序。这是因为,和我们现在使用的C++、C#这种面向对象的语言不同,OpenGL中的大多数函数使用了一种基于状态的方法,大多数OpenGL对象都需要在使用前把该对象绑定到context上。这里有两个新名词——OpenGL对象和Context。
Context
Context是一个非常抽象的概念,我们姑且把它理解成一个包含了所有OpenGL状态的对象。如果我们把一个Context销毁了,那么OpenGL也不复存在。
OpenGL对象
我们可以把OpenGL对象理解成一个状态的集合,它负责管理它下属的所有状态。当然,除了状态,OpenGL对象还会存储其他数据。注意。这些状态和上述context中的状态并不重合,只有在把一个OpenGL对象绑定到context上时,OpenGL对象的各种状态才会映射到context的状态。因此,这时如果我们改变了context的状态,那么也会影响这个对象,而相反地,依赖这些context状态的函数也会使用存储在这个对象上的数据。
下面看一个实例:
源码下载地址:https://download.csdn.net/download/cqltbe131421/10502444

#include "mainwidget.h"
#include <QMouseEvent>
#include <math.h>
#include <QDebug>
MainWidget::MainWidget(QWidget *parent) :
    QOpenGLWidget(parent),
    geometries(0),
    texture(0),
    angularSpeed(0)
{
}

MainWidget::~MainWidget()
{
    // 删除纹理时确保上下文是当前的
    // 缓冲器。
    makeCurrent();
    delete texture;
    delete geometries;
    doneCurrent();
}

void MainWidget::mousePressEvent(QMouseEvent *e)
{
    //保存鼠标按下位置
    mousePressPosition = QVector2D(e->localPos());
}

void MainWidget::mouseMoveEvent(QMouseEvent *e)
{
    // 鼠标释放位置-鼠标按下位置
    QVector2D diff = QVector2D(e->localPos()) - mousePressPosition;
    //旋转轴垂直于鼠标位置差
    // vector
    QVector3D n = QVector3D(diff.y(), diff.x(), 0.0).normalized();
    //相对于鼠标扫描长度加快角速度
    qreal acc = diff.length() / 100.0;
    // 计算新的旋转轴作为加权和
    rotationAxis = (rotationAxis * angularSpeed + n * acc).normalized();
    // 提高角速度
    angularSpeed = acc;
    // 如果加等的话会更快
    //    angularSpeed += acc;
    rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed) * rotation;
    update();
}

void MainWidget::timerEvent(QTimerEvent *)
{
    // 降低角速度(摩擦)
    angularSpeed *= 0.99;
    // 当停止旋转速度都低于阈值
    if (angularSpeed < 0.01) {
        angularSpeed = 0.0;
    } else {
        //更新轮换
        rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed) * rotation;
        // 请求更新
        update();
    }
}

void MainWidget::initializeGL()
{
    initializeOpenGLFunctions();//初始化gl
    glClearColor(0, 0, 0, 1);//清除颜色
    initShaders();//初始化着色器
    initTextures();//初始化纹理
    // 启用深度缓冲区
    glEnable(GL_DEPTH_TEST);
    // 启用背面剔除
    glEnable(GL_CULL_FACE);
    geometries = new GeometryEngine;//绘图矩阵
    // 使用QBasic定时器,因为它比QTIMER快
    timer.start(12, this);
}

void MainWidget::initShaders()
{
    // 编译顶点着色器,添加资源
    if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vshader.glsl")){
        close();
    }
    //编译片段着色器,添加资源
    if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fshader.glsl")){
        close();
    }
    //链接着色器管道
    if (!program.link()){
        close();
    }
    // 绑定着色器管道以供使用
    if (!program.bind())
        close();
}

void MainWidget::initTextures()
{
    // 加载图像
    texture = new QOpenGLTexture(QImage(":/test.png").mirrored());
    // 设置纹理最小化的最近过滤模式
    texture->setMinificationFilter(QOpenGLTexture::Nearest);
    //纹理放大的双线性滤波模式
    texture->setMagnificationFilter(QOpenGLTexture::Linear);
    // 重复纹理贴图坐标
    // f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
    texture->setWrapMode(QOpenGLTexture::Repeat);
}

void MainWidget::resizeGL(int w, int h)
{
    //calculate方面比
    qreal aspect = qreal(w) / qreal(h ? h : 1);
    // 设近平面为3,远平面为7,视场为45度
    const qreal zNear = 3.0, zFar = 7.0, fov = 45.0;
    // 复位投影
    projection.setToIdentity();
    // 集合透视投影
    projection.perspective(fov, aspect, zNear, zFar);
}

void MainWidget::paintGL()
{
    // 清除的颜色和深度缓冲器
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    texture->bind();//绑定
    // 计算模型视图变换
    QMatrix4x4 matrix;
    matrix.translate(0.0, 0.0, -5.0);//平移
    matrix.rotate(rotation);//旋转
    //集合模型视图投影矩阵
    program.setUniformValue("mvp_matrix", projection * matrix);
    // 使用纹理单元,包含cube.png 0
    program.setUniformValue("texture", 0);
    //绘制立方体几何图形
    geometries->drawCubeGeometry(&program);
}

#include "geometryengine.h"
#include <QVector2D>
#include <QVector3D>

struct VertexData
{
    QVector3D position;
    QVector2D texCoord;
};

//! [0]
GeometryEngine::GeometryEngine()
    : indexBuf(QOpenGLBuffer::IndexBuffer)
{
    initializeOpenGLFunctions();//初始化
    // Generate 2 VBOs
    arrayBuf.create();//创建
    indexBuf.create();//创建
    // Initializes cube geometry and transfers it to VBOs
    initCubeGeometry();
}

GeometryEngine::~GeometryEngine()
{
    arrayBuf.destroy();//释放
    indexBuf.destroy();
}

void GeometryEngine::initCubeGeometry()
{
    // 对于立方体,我们只需要8个顶点,但是我们必须
    // 因为纹理坐标不同,所以每个面都有顶点。
    VertexData vertices[] = {
        // Vertex data for face 0
        {QVector3D(-1.0f, -1.0f,  1.0f), QVector2D(0.0f, 0.0f)},  // v0
        {QVector3D( 1.0f, -1.0f,  1.0f), QVector2D(0.33f, 0.0f)}, // v1
        {QVector3D(-1.0f,  1.0f,  1.0f), QVector2D(0.0f, 0.5f)},  // v2
        {QVector3D( 1.0f,  1.0f,  1.0f), QVector2D(0.33f, 0.5f)}, // v3

        // Vertex data for face 1
        {QVector3D( 1.0f, -1.0f,  1.0f), QVector2D( 0.0f, 0.5f)}, // v4
        {QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.33f, 0.5f)}, // v5
        {QVector3D( 1.0f,  1.0f,  1.0f), QVector2D(0.0f, 1.0f)},  // v6
        {QVector3D( 1.0f,  1.0f, -1.0f), QVector2D(0.33f, 1.0f)}, // v7

        // Vertex data for face 2
        {QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.5f)}, // v8
        {QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(1.0f, 0.5f)},  // v9
        {QVector3D( 1.0f,  1.0f, -1.0f), QVector2D(0.66f, 1.0f)}, // v10
        {QVector3D(-1.0f,  1.0f, -1.0f), QVector2D(1.0f, 1.0f)},  // v11

        // Vertex data for face 3
        {QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.0f)}, // v12
        {QVector3D(-1.0f, -1.0f,  1.0f), QVector2D(1.0f, 0.0f)},  // v13
        {QVector3D(-1.0f,  1.0f, -1.0f), QVector2D(0.66f, 0.5f)}, // v14
        {QVector3D(-1.0f,  1.0f,  1.0f), QVector2D(1.0f, 0.5f)},  // v15

        // Vertex data for face 4
        {QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(0.33f, 0.0f)}, // v16
        {QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.0f)}, // v17
        {QVector3D(-1.0f, -1.0f,  1.0f), QVector2D(0.33f, 0.5f)}, // v18
        {QVector3D( 1.0f, -1.0f,  1.0f), QVector2D(0.66f, 0.5f)}, // v19

        // Vertex data for face 5
        {QVector3D(-1.0f,  1.0f,  1.0f), QVector2D(0.33f, 0.5f)}, // v20
        {QVector3D( 1.0f,  1.0f,  1.0f), QVector2D(0.66f, 0.5f)}, // v21
        {QVector3D(-1.0f,  1.0f, -1.0f), QVector2D(0.33f, 1.0f)}, // v22
        {QVector3D( 1.0f,  1.0f, -1.0f), QVector2D(0.66f, 1.0f)}  // v23
    };

    // Indices for drawing cube faces using triangle strips.
    // Triangle strips can be connected by duplicating indices
    // between the strips. If connecting strips have opposite
    // vertex order then last index of the first strip and first
    // index of the second strip needs to be duplicated. If
    // connecting strips have same vertex order then only last
    // index of the first strip needs to be duplicated.
    GLushort indices[] = {
         0,  1,  2,  3,  3,     // Face 0 - triangle strip ( v0,  v1,  v2,  v3)
         4,  4,  5,  6,  7,  7, // Face 1 - triangle strip ( v4,  v5,  v6,  v7)
         8,  8,  9, 10, 11, 11, // Face 2 - triangle strip ( v8,  v9, v10, v11)
        12, 12, 13, 14, 15, 15, // Face 3 - triangle strip (v12, v13, v14, v15)
        16, 16, 17, 18, 19, 19, // Face 4 - triangle strip (v16, v17, v18, v19)
        20, 20, 21, 22, 23      // Face 5 - triangle strip (v20, v21, v22, v23)
    };

    // Transfer vertex data to VBO 0
    arrayBuf.bind();
    arrayBuf.allocate(vertices, 24 * sizeof(VertexData));

    // Transfer index data to VBO 1
    indexBuf.bind();
    indexBuf.allocate(indices, 34 * sizeof(GLushort));
}

void GeometryEngine::drawCubeGeometry(QOpenGLShaderProgram *program)
{
    // 告诉OpenGL使用哪些VBOS
    arrayBuf.bind();
    indexBuf.bind();
    //位置偏移
    quintptr offset = 0;
    // 告诉OpenGL可编程流水线如何定位顶点位置数据
    int vertexLocation = program->attributeLocation("a_position");
    program->enableAttributeArray(vertexLocation);
    program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData));

    // 纹理坐标偏移
    offset += sizeof(QVector3D);
    // 告诉OpenGL可编程流水线如何定位顶点纹理坐标数据
    int texcoordLocation = program->attributeLocation("a_texcoord");
    program->enableAttributeArray(texcoordLocation);
    program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));
    // 使用VBO 1索引绘制立方体几何图形
    glDrawElements(GL_TRIANGLE_STRIP, 34, GL_UNSIGNED_SHORT, 0);
}


这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vqt5_qt6

你的鼓励是我们创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值