Qt+OpenGL入门教程(三)——绘制三角形

通过前两篇文章的学习,我想大家应该有了基本的理解,我们接下来实操一下。

创建Qt OpenGL窗口

QOpenGLWidget

QGLWidget是传统QtOpenGL模块的一部分,与其他QGL类一样,应该在新的应用程序中避免使用。相反,从Qt5.4开始,Qt推荐使用QOpenGLWidget和QOpenGL类。

QOpenGLWidget提供显示集成到Qt应用程序中的OpenGL图形的功能,使用起来非常简单。让类继承它,并像其他QWidget一样使用子类,额外可以选择使用QPainer和标准的OpenGL渲染命令。

QOpenGLWidget提供了三个方便的虚拟函数,可以在子类中重新实现这些函数来执行典型的OpenGL任务:

  • initializeGL():设置OpenGL呈现上下文,定义显示列表等。在第一次调用resizeGL()或paintGL()之前调用一次。
  • resizeGL():设置OpenGL视区、投影等。每当调整了大小时都会调用该视区(并且当它第一次显示时也会调用,因为所有新创建的小部件都会自动获得一个调整大小的事件)。
  • paintGL():渲染OpenGL场景。每当需要更新小部件时调用。

QOpenGLExtraFunctions

QOpenGLExtraFunctions类继承于QOpenGLFunctions,相较于QOpenGLFunctions,额外提供了对OpenGL ES 3.0、3.1和3.2 API的跨平台访问,如果我们需要在类中使用opengl函数,只需要使类继承于QOpenGLExtraFunctions,就能在内部通过this指针访问到OpenGL函数

QOpenGLShaderProgram

QOpenGLShaderProgram是Qt中用于管理OpenGL着色器程序的类。它封装了OpenGL的着色器对象(Shader Object)和着色器程序对象(Shader Program Object),提供了一种方便的方式来管理和使用着色器。

标准化设备坐标(Normalized Device Coordinates, NDC)

顶点着色器中处理过后,就应该是标准化设备坐标了,x、y和z的值在-1.0到1.0的一小段空间(立方体)。落在范围外的坐标都会被裁剪。下面代码中顶点数据的坐标就是使用该坐标。

源码

CMakeLists.txt

C++ 复制代码
cmake_minimum_required(VERSION 3.5)

project(Day01 VERSION 0.1 LANGUAGES CXX)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

// 注意添加OpenGL模块
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets OpenGL)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets OpenGL)

set(PROJECT_SOURCES
    main.cpp
    widget.cpp
    widget.h
)

add_executable(Day01
    ${PROJECT_SOURCES}
    shader.qrc
)

target_link_libraries(Day01 PRIVATE
    Qt${QT_VERSION_MAJOR}::Widgets
    Qt${QT_VERSION_MAJOR}::OpenGL
)

widget.h

C++ 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLShaderProgram>

/**
 * 绘制窗口
 */
class Widget : public QOpenGLWidget, protected QOpenGLExtraFunctions
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

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

private:
    QOpenGLShaderProgram shaderProgram;
};
#endif // WIDGET_H

widget.cpp

C++ 复制代码
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QOpenGLWidget(parent)
{
}

Widget::~Widget()
{
}

void Widget::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    shaderProgram.create();
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/gl.vert");
    shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl.frag");
    shaderProgram.link();

    // 开启着色器程序的pos属性
    shaderProgram.enableAttributeArray("pos");
}

void Widget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void Widget::paintGL()
{
    shaderProgram.bind();

    GLfloat vertices[] = {
        0.0f, 0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        -0.5f, -0.5f, 0.0f,
    };

    // 设置顶点数据的数据来源,从vertices数组中读取,且每三个数据作为一个顶点数据(vec3)
    shaderProgram.setAttributeArray("pos", vertices, 3);
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

gl.vert

复制代码
in vec3 pos;

void main(void)
{
    gl_Position = vec4(pos, 1.0);
}

gl.frag

复制代码
void main(void)
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

结果展示:

在此我们就绘制成功啦!赶紧动手试试吧,不用太在意里面的细节,后面会更详细的讲解。

相关推荐
SunkingYang42 分钟前
QT程序如何将事件和消息发送给MFC程序,MFC程序如何接收消息和事件
qt·mfc·消息·事件·通信·通讯·传递
凯子坚持 c2 小时前
Qt 5.14.0 入门框架开发全流程深度解析
开发语言·qt
深蓝海拓3 小时前
PySide6从0开始学习的笔记(十四)创建一个简单的实用UI项目
开发语言·笔记·python·qt·学习·ui·pyqt
小尧嵌入式3 小时前
Linux网络介绍网络编程和数据库
linux·运维·服务器·网络·数据库·qt·php
海涛高软4 小时前
Qt中使用QListWidget列表
开发语言·qt
010米粉0104 小时前
Qt之构建方式
qt
凯子坚持 c5 小时前
Qt 信号与槽机制深度解析
开发语言·qt
世转神风-5 小时前
qt-初步编译运行报错-When executing step “Make“-无法启动进程“make“
开发语言·qt
一然明月16 小时前
QT之基础控件
开发语言·qt
深蓝海拓21 小时前
PySide6从0开始学习的笔记(十) 样式表(QSS)
笔记·python·qt·学习·pyqt