欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在Qt中使用OpenGL繪制三角形指南

 更新時間:2025年04月07日 08:48:39   作者:師從名劍山  
在高性能渲染場景中,CPU資源常被過度消耗,導(dǎo)致界面卡頓,而OpenGL作為業(yè)界標(biāo)準(zhǔn)的圖形API,能通過GPU硬件加速顯著降低CPU負(fù)載,本文將以繪制三角形為例,教你如何通過Qt的QOpenGLWidget和QOpenGLFunctions實現(xiàn)跨平臺GPU渲染,感興趣的朋友一起看看吧

本文只介紹基本的 QOpenGLWidget 和 QOpenGLFunctions 的使用,想要學(xué)習(xí) OpenGL 的朋友,建議訪問經(jīng)典 OpenGL 學(xué)習(xí)網(wǎng)站:LearnOpenGL CN

本篇文章,我們將以繪制一個經(jīng)典的三角形為例,講一講,怎么在 Qt 中使用 OpenGL 來進(jìn)行 GPU 繪制。

前言

在高性能渲染場景中,CPU資源常被過度消耗,導(dǎo)致界面卡頓。而OpenGL作為業(yè)界標(biāo)準(zhǔn)的圖形API,能通過GPU硬件加速顯著降低CPU負(fù)載。本文將以繪制三角形為例,教你如何通過Qt的QOpenGLWidget和QOpenGLFunctions實現(xiàn)跨平臺GPU渲染。

QOpenGLFunctions

OpenGL函數(shù)在不同平臺(Windows/Linux/Mac)的實現(xiàn)存在差異。例如:

平臺函數(shù)加載方式
WindowswglGetProcAddress
LinuxglXGetProcAddress

Qt通過QOpenGLFunctions封裝了這些底層差異,開發(fā)者只需繼承此類,即可用glClear() 等統(tǒng)一接口調(diào)用OpenGL函數(shù),無需編寫平臺特定代碼。通過這樣,我們就可以用一套代碼,在不同平臺下使用 OpenGL 相。要使用這個類也很簡單,讓我們的類直接繼承 QOpenGLFuntions 就好了。同時也可以配合 QOpenGLWidget 來使用,在 initializeGL 函數(shù)里,調(diào)用 initializeOpenGLFunctions 后,就可以直接使用 OpenGL 的函數(shù)

Windows 下加載(wglGetProcAddress)

例如在 Windows 下,我們使用 wglGetProcAddress來動態(tài)加載這些函數(shù)(例如 glClear),下面是加載代碼:

包含必要的頭文件

#include <windows.h>
#include <GL/gl.h>
#include <GL/glext.h>  // 提供 OpenGL 擴(kuò)展聲明

定義函數(shù)指針類型

// 示例:定義 glClear 的函數(shù)指針類型
typedef void (APIENTRY *PFNGLCLEARPROC)(GLbitfield);
PFNGLCLEARPROC glClear;

加載 OpenGL 函數(shù)

// 初始化 OpenGL 函數(shù)
void initOpenGLFunctions() {
    // 1. 加載 OpenGL 1.1 函數(shù)(由 opengl32.dll 提供)
    glClear = (PFNGLCLEARPROC)wglGetProcAddress("glClear");
    // 2. 檢查是否加載成功
    if (!glClear) {
        // 如果失敗,可能是驅(qū)動不支持該函數(shù)
        MessageBoxA(NULL, "Failed to load glClear", "Error", MB_OK);
        exit(1);
    }
    // 3. 類似方式加載其他函數(shù)...
    // glDrawArrays = (PFNGLDRAWARRAYSPROC)wglGetProcAddress("glDrawArrays");
    // ...
}

使用加載的函數(shù)

glClear(GL_COLOR_BUFFER_BIT);  // 現(xiàn)在可以正常調(diào)用

Linux 下加載(glXGetProcAddress )

而在 linux 下,加載的函數(shù)變成了:glXGetProcAddress ,對應(yīng)的代碼是:

包含必要的頭文件

#include <GL/gl.h>
#include <GL/glx.h>  // X11 的 OpenGL 擴(kuò)展
#include <GL/glext.h>

定義函數(shù)指針類型

// 示例:定義 glClear 的函數(shù)指針類型
typedef void (*PFNGLCLEARPROC)(GLbitfield);
PFNGLCLEARPROC glClear;

加載 OpenGL 函數(shù)

void initOpenGLFunctions() {
    // 1. 加載 glClear
    glClear = (PFNGLCLEARPROC)glXGetProcAddress((const GLubyte*)"glClear");
    // 2. 檢查是否加載成功
    if (!glClear) {
        fprintf(stderr, "Failed to load glClear\n");
        exit(1);
    }
    // 3. 類似方式加載其他函數(shù)...
    // glDrawArrays = (PFNGLDRAWARRAYSPROC)glXGetProcAddress((const GLubyte*)"glDrawArrays");
    // ...
}

使用加載的函數(shù)

glClear(GL_COLOR_BUFFER_BIT);  // 現(xiàn)在可以正常調(diào)用

QOpenGLWidget

QOpenGLWidget 是 Qt 提供的一個 widget 類,用于在 Qt 應(yīng)用程序中嵌入 OpenGL 渲染內(nèi)容。它繼承自 QWidget,內(nèi)部管理了一個 OpenGL 上下文(例如 windows 下調(diào)用 wglMakeCurrent / wglDoneCurrent)和幀緩沖區(qū),并提供了與 Qt 窗口系統(tǒng)無縫集成的能力。詳細(xì)內(nèi)容可看:QOpenGLWidget Class

我們可以創(chuàng)建自己的窗口,并繼承 QOpenGLWidget,然后重寫下面三個函數(shù),來處理一些 OpenGL 相關(guān)的工作。

initializeGL

初始化一些 OpenGL 相關(guān)的資源或者狀態(tài)。這個函數(shù)在在第一次調(diào)用 resizeGL或者 paintGL之前被調(diào)用。

paintGL

渲染 OpenGL 的場景,類似于我們平常使用的 QWidget::paintEvent,在窗口需要更新時調(diào)用。

resizeGL

調(diào)整 OpenGL Viewport 的大小或者投影等,在窗口需要調(diào)整大小時調(diào)用。

完整代碼

#pragma once
#include <QOpenGLBuffer>
#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include "FrameObserver.h"
class COpenGLRenderWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT
public:
    explicit COpenGLRenderWidget(QWidget *parent = nullptr);
    ~COpenGLRenderWidget() override;
private:
    void InitShaders();
private:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;
private:
    QOpenGLShaderProgram m_shaderProgram;
    QOpenGLBuffer m_vbo;
};
#include "OpenGLRenderWidget.h"
static const GLfloat coordinateBasic[] = {
    // 頂點(diǎn)坐標(biāo),存儲3個xyz坐標(biāo)
    // x     y     z
    -0.5f, -0.5f, 0.0f,
     0.5f, -0.5f, 0.0f,
     0.0f,  0.5f, 0.0f,
};
constexpr auto VERTEX_SHADER_BASIC = R"(
attribute vec3 vertexIn; 
varying vec2 textureOut; 
void main(void)
{
    gl_Position = vec4(vertexIn, 1.0);
}
)";
constexpr auto FRAGMENT_SHADER_BASIC = R"(
varying vec2 textureOut;
void main(void) 
{ 
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 
}
)";
COpenGLRenderWidget::COpenGLRenderWidget(QWidget *parent)
    : QOpenGLWidget(parent)
{}
COpenGLRenderWidget::~COpenGLRenderWidget()
{}
void COpenGLRenderWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glDisable(GL_DEPTH_TEST);
    m_vbo.create();
    m_vbo.bind();
    m_vbo.allocate(coordinateBasic, sizeof(coordinateBasic));
    InitShaders();
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
}
void COpenGLRenderWidget::paintGL()
{
    m_shaderProgram.bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);
    m_shaderProgram.release();
}
void COpenGLRenderWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
    update();
}
void COpenGLRenderWidget::InitShaders()
{
    QOpenGLShader vertexShader(QOpenGLShader::Vertex);
    if (!vertexShader.compileSourceCode(VERTEX_SHADER_BASIC))
    {
        qDebug() << "Vertex shader compilation failed. Error: " << vertexShader.log();
        return;
    }
    QOpenGLShader fragmentShader(QOpenGLShader::Fragment);
    if (!fragmentShader.compileSourceCode(FRAGMENT_SHADER_BASIC))
    {
        qDebug() << "Fragment shader compilation failed. Error: " << fragmentShader.log();
        return;
    }
    m_shaderProgram.addShader(&vertexShader);
    m_shaderProgram.addShader(&fragmentShader);
    m_shaderProgram.link();
    m_shaderProgram.bind();
    m_shaderProgram.setAttributeBuffer("vertexIn", GL_FLOAT, 0, 3, 3 * sizeof(float));
    m_shaderProgram.enableAttributeArray("vertexIn");
}

到此這篇關(guān)于在Qt中使用OpenGL繪制指南的文章就介紹到這了,更多相關(guān)Qt使用OpenGL繪制指南內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++實現(xiàn)strcmp字符串比較的深入探討

    C++實現(xiàn)strcmp字符串比較的深入探討

    本篇文章是對使用C++實現(xiàn)strcmp字符串比較進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++類模板以及保存數(shù)據(jù)到文件方式

    C++類模板以及保存數(shù)據(jù)到文件方式

    這篇文章主要介紹了C++類模板以及保存數(shù)據(jù)到文件方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 線程池的原理與實現(xiàn)詳解

    線程池的原理與實現(xiàn)詳解

    下面利用C語言來實現(xiàn)一個簡單的線程池,為了使得這個線程池庫使用起來更加方便,特在C實現(xiàn)中加入了一些OO的思想,與Objective-C不同,它僅僅是使用了struct來模擬了c++中的類,其實這種方式在linux內(nèi)核中大量可見
    2013-09-09
  • C語言實現(xiàn)簡易計算器功能

    C語言實現(xiàn)簡易計算器功能

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)簡易計算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • c++歸并排序詳解

    c++歸并排序詳解

    歸并排序遵循分治法的思想:將原問題分解為幾個規(guī)模較小但類似于原問題的子問題,遞歸地求解這些子問題,然后再合并這些子問題的解來建立原問題的解。分治模式在每層遞歸時都有三個步驟:分解、解決、合并。歸并排序完全遵循該模式。
    2017-05-05
  • 詳細(xì)分析Android中實現(xiàn)Zygote的源碼

    詳細(xì)分析Android中實現(xiàn)Zygote的源碼

    這篇文章主要介紹了詳細(xì)分析Android中實現(xiàn)Zygote的源碼,包括底層的C/C++代碼以及Java代碼部分入口,需要的朋友可以參考下
    2015-07-07
  • C++ 異常處理 catch(...)介紹

    C++ 異常處理 catch(...)介紹

    catch(…)能夠捕獲多種數(shù)據(jù)類型的異常對象,所以它提供給程序員一種對異常 對象更好的控制手段,使開發(fā)的軟件系統(tǒng)有很好的可靠性
    2013-09-09
  • 如何在C語言中提取Shellcode并執(zhí)行

    如何在C語言中提取Shellcode并執(zhí)行

    Shellcode是一種獨(dú)立于應(yīng)用程序的機(jī)器代碼,通常用于實現(xiàn)特定任務(wù),如執(zhí)行遠(yuǎn)程命令、注入惡意軟件或利用系統(tǒng)漏洞,本文將深入探討如何在C語言中提取Shellcode,并通過XOR加密技術(shù)增加其混淆程度,文中通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • C++手寫內(nèi)存池的案例詳解

    C++手寫內(nèi)存池的案例詳解

    這篇文章主要介紹了C++手寫內(nèi)存池的案例詳解,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • C++中類的默認(rèn)成員函數(shù)詳解

    C++中類的默認(rèn)成員函數(shù)詳解

    大家好,本篇文章主要講的是C++中類的默認(rèn)成員函數(shù)詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01

最新評論