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);
}

结果展示:

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

相关推荐
神仙别闹2 小时前
基于 QT(C++)开发的地铁换乘系统
数据库·c++·qt
C++ 老炮儿的技术栈5 小时前
西门子 S7 常用存储区(I/Q/M/T/C/DB/PI/PQ)
linux·开发语言·c++·windows·qt·io
郝学胜-神的一滴7 小时前
C++11 工程级应用 10:减少拷贝,让容器跑得更快
服务器·开发语言·c++·游戏引擎·opengl
j7~8 小时前
【Qt】(篇二)《信号与槽:信号和槽的概述,使用、自定义信号和槽、信号与槽的连接方式、信号和槽的其他说明》---详解
qt·信号·qt5·信号与槽··qt creater
Littlehero_1211 天前
QT自定义控件之电气接线图(源码开源)
开发语言·qt
qq762118221 天前
Ubuntu22.04 Qt 调用shell 脚本启动程序,GLFW 初始化失败
qt
蓝悦无人机1 天前
Qt Design Studio(QDS)4.8.2项目文件结构详解
开发语言·qt·qt creator·qds·项目文件结构·qtc
qq_401700411 天前
Qt窗体大小控制从resize到自适应
开发语言·qt
Quz1 天前
QML SwipeView:手势翻页与自定义指示器
qt
Quz1 天前
QML TabBar组件与容器索引的绑定
qt