完整例子和調用關系qt OpenGL

項目結構

首先,你需要在 Qt 項目中創建一個類,繼承自 QOpenGLWidget 來進行 OpenGL 渲染。文件結構如下:
- main.cpp
- MyOpenGLWidget.h
- MyOpenGLWidget.cpp
- vertex_shader.glsl
- fragment_shader.glsl

1. main.cpp

這是 Qt 項目的入口文件,創建一個 QApplication 實例并顯示一個包含 QOpenGLWidget 的窗口。
// 包含 Qt 應用程序的核心類,用于管理 Qt 應用程序的控制流。
#include <QApplication>// 包含 Qt 的主窗口類,可以創建一個包含菜單、工具欄等常見組件的窗口。
#include <QMainWindow>// 包含我們自定義的 OpenGL 渲染窗口類。
#include "MyOpenGLWidget.h"int main(int argc, char *argv[]) {/* 初始化 Qt 應用程序。argc 和 argv 是命令行參數,通常用來傳遞命令行參數到程序中。QApplication 是所有 Qt 應用程序的基礎,它管理應用程序的生命周期和事件循環。*/QApplication app(argc, argv);// 創建一個主窗口對象 window,它是應用程序的主界面。QMainWindow window;// 創建自定義的 OpenGL 渲染窗口 glWidget。// &window 將主窗口 window 作為父窗口傳遞給 glWidget。MyOpenGLWidget *glWidget = new MyOpenGLWidget(&window);// 將 glWidget 設為 window 的中心部件。// QMainWindow 中的中心部件通常占據主窗口的最大區域。window.setCentralWidget(glWidget);// 設置窗口大小window.resize(800, 600);// 顯示窗口window.show();return app.exec();
}

2. MyOpenGLWidget.h

這是聲明文件,繼承自 QOpenGLWidget 和 QOpenGLFunctions, 用于處理 OpenGL 渲染。在這里,我們聲明必要的 OpenGL 初始化、繪制和清理函數。
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H// 包含 Qt 的 OpenGL 小部件類,這樣我們可以創建一個 OpenGL 渲染窗口。
#include <QOpenGLWidget>
// 包含 OpenGL 功能的接口。我們可以通過這個類訪問 OpenGL 的核心功能。
#include <QOpenGLFunctions>
// 包含 OpenGL 著色器程序類,負責加載、編譯、鏈接和管理著色器程序。
#include <QOpenGLShaderProgram>
// 包含 OpenGL 緩沖區類,負責創建和管理頂點緩沖對象(VBO)和索引緩沖對象(EBO)。
#include <QOpenGLBuffer>/* 聲明一個名為 MyOpenGLWidget 的類,繼承自 QOpenGLWidget 和 QOpenGLFunctions。QOpenGLWidget 是 Qt 提供的 OpenGL 渲染窗口基類,QOpenGLFunctions 提供了 OpenGL 的基本功能。protected QOpenGLFunctions 是為了能夠訪問 OpenGL 的函數接口。
*/
class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {Q_OBJECTpublic:MyOpenGLWidget(QWidget *parent = nullptr);~MyOpenGLWidget();protected:// 初始化 OpenGL 環境的函數。// 在這里你會設置 OpenGL 的狀態,例如開啟深度測試、設置視口、加載著色器等。void initializeGL() override;// 當窗口大小改變時自動調用。你可以在這里設置 OpenGL 視口以及投影矩陣。void resizeGL(int w, int h) override;// 每次需要重新繪制時調用。在這里繪制 OpenGL 圖形。void paintGL() override;private:// 用于初始化并編譯著色器的函數。void initializeShaders();// 用于初始化頂點數據和緩沖區的函數。void initializeBuffers();// 指向 OpenGL 著色器程序的指針。用于管理著色器的加載、編譯、鏈接和綁定。QOpenGLShaderProgram *shaderProgram;// 一個 QOpenGLBuffer 對象,用于存儲頂點數據的緩沖區(VBO)。QOpenGLBuffer vertexBuffer;        // 頂點數組對象的句柄。VAO 用于管理頂點屬性和緩沖區對象。GLuint VAO, VBO;                          
};#endif // MYOPENGLWIDGET_H

3. MyOpenGLWidget.cpp

這是實現文件,包含了 OpenGL 初始化、著色器編譯、數據傳輸和渲染的具體代碼。
#include "MyOpenGLWidget.h"
// 包含 OpenGL 著色器類,負責加載著色器代碼并編譯它們。
#include <QOpenGLShader>
#include <QOpenGLBuffer>
#include <QDebug>MyOpenGLWidget::MyOpenGLWidget(QWidget *parent): QOpenGLWidget(parent),shaderProgram(nullptr) 
{
}MyOpenGLWidget::~MyOpenGLWidget() {// 銷毀 shaderProgram,釋放著色器程序的內存。delete shaderProgram;
}void MyOpenGLWidget::initializeGL() {// 1. 初始化 OpenGL 函數,確保可以使用 OpenGL 的所有函數。initializeOpenGLFunctions();// 啟用深度測試,確保物體在 3D 場景中的正確顯示(即前面物體遮擋后面物體)。glEnable(GL_DEPTH_TEST);  // 2. 初始化著色器程序initializeShaders();// 3. 初始化頂點數據initializeBuffers();
}void MyOpenGLWidget::initializeShaders() {// 2.1 創建并編譯頂點著色器// 創建一個新的著色器程序對象。shaderProgram = new QOpenGLShaderProgram();// 加載并編譯頂點著色器,QOpenGLShader::Vertex 指明這是頂點著色器,文件路徑為 :/vertex_shader.glsl。shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex_shader.glsl");// 加載并編譯片段著色器,QOpenGLShader::Fragment 指明這是片段shaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment_shader.glsl");// 2.2 鏈接著色器程序shaderProgram->link();shaderProgram->bind();
}void MyOpenGLWidget::initializeBuffers() {// 3.1 頂點數據(一個簡單的三角形)GLfloat vertices[] = {-1.0f,  1.0f, 0.0f,   // 頂點1-1.0f, -1.0f, 0.0f,   // 頂點21.0f, -1.0f, 0.0f    // 頂點3};// 3.2 創建 VAO 和 VBOglGenVertexArrays(1, &VAO);  // 創建 VAOglBindVertexArray(VAO);      // 綁定 VAOglGenBuffers(1, &VBO);       // 創建 VBOglBindBuffer(GL_ARRAY_BUFFER, VBO);  // 綁定 VBOglBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 分配數據給 VBO// 3.3 設置頂點屬性(位置)// 啟用頂點屬性(位置屬性)shaderProgram->enableAttributeArray(0);// 設置位置數據的格式shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, 3 * sizeof(GLfloat));vertexBuffer.release();  // 釋放 VBOglBindVertexArray(0);  // 解綁 VAO
}void MyOpenGLWidget::resizeGL(int w, int h) {// 4. 設置視口大小glViewport(0, 0, w, h);// 4.1 設置投影矩陣(透視投影)glMatrixMode(GL_PROJECTION); // 設定當前矩陣為投影矩陣glLoadIdentity();  // 重置當前矩陣// 設置透視投影gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 0.1, 100.0);// 切換回模型視圖矩陣glMatrixMode(GL_MODELVIEW);
}void MyOpenGLWidget::paintGL() {// 5. 清空屏幕并準備繪制// 清空顏色和深度緩沖glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity();// 5.1 使用著色器程序shaderProgram->bind();glBindVertexArray(VAO);// 5.2 繪制三角形// 使用頂點數據繪制三角形glDrawArrays(GL_TRIANGLES, 0, 3);glBindVertexArray(0);shaderProgram->release();
}

4. vertex_shader.glsl

頂點著色器(將頂點位置傳遞給片段著色器):
#version 330 core
layout(location = 0) in vec3 position;
void main() {gl_Position = vec4(position, 1.0);  // 直接輸出位置
}

5. fragment_shader.glsl

片段著色器(指定最終顏色):
#version 330 core
out vec4 color;
void main() {color = vec4(1.0, 0.0, 0.0, 1.0);  // 輸出紅色
}


函數作用說明

  • initializeGL():負責 OpenGL 環境的初始化工作,包括啟用深度測試、初始化著色器和頂點數據。這個函數會在 QOpenGLWidget 創建后自動調用。
  • initializeShaders():編譯頂點和片段著色器,并將它們鏈接成一個 OpenGL 程序。著色器代碼通常存儲在外部文件中,這里用 addShaderFromSourceFile() 來加載。
  • initializeBuffers():創建并初始化頂點緩沖對象(VBO)和頂點數組對象(VAO)。VBO 存儲頂點數據,而 VAO 用于管理 VBO 的狀態。頂點數據傳送到 GPU 后,OpenGL 會使用它來繪制物體
  • resizeGL(int w, int h):用于處理 OpenGL 上下文的大小變化,設置視口以及投影矩陣,使得繪制的圖形不會在窗口大小變化時失真。
  • paintGL():這個函數每次需要重新繪制時都會被調用。這里,我們清空屏幕,使用著色器程序,并通過 glDrawArrays() 繪制三角形。

調用關系和邏輯

  1. 在程序啟動時,QOpenGLWidget 的構造函數會被調用。QOpenGLWidget 會創建一個 OpenGL 上下文,并在需要時調用 initializeGL()。
  2. 在 initializeGL() 中,我們初始化 OpenGL 狀態(如深度測試),然后調用 initializeShaders() 來加載并編譯著色器程序,接著調用 initializeBuffers() 初始化頂點數據。
  3. 每當窗口大小改變時,resizeGL() 會被自動調用來調整視口大小和設置合適的投影矩陣。
  4. 每次需要繪制時(例如每幀刷新時),paintGL() 會被調用。在此函數中,我們綁定著色器程序、頂點數組對象(VAO),并通過 glDrawArrays() 來繪制三角形。

總結

  • initializeGL() -> 調用 initializeShaders() 初始化著色器,調用 initializeBuffers() 初始化頂點數據。
  • paintGL() -> 每次繪制時使用著色器和頂點數據。
  • resizeGL() -> 當窗口大小變化時調整視口和投影矩陣。

疑惑補充:

QOpenGLShaderProgram 對象-CSDN博客

OpenGL疑惑-CSDN博客

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/73176.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/73176.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/73176.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

VSCode 配置優化指南:打造極致高效的前端開發環境

VSCode 配置優化指南&#xff1a;打造極致高效的前端開發環境 一、基礎環境配置&#xff1a;讓開發更流暢 1. 性能優化設置 // settings.json {"files.autoSave": "afterDelay", // 自動保存&#xff08;延遲1秒&#xff09;"files.exclud…

源IP泄露后如何涅槃重生?高可用架構與自動化防御體系設計

一、架構層解決方案 1. 高防代理架構設計 推薦架構&#xff1a; 用戶 → CDN&#xff08;緩存靜態資源&#xff09; → 高防IP&#xff08;流量清洗&#xff09; → 源站集群&#xff08;真實IP隱藏&#xff09; ↑ Web應用防火墻&#xff08;WAF&#xff09; 實施要點&a…

【英偉達AI論文】多模態大型語言模型的高效長視頻理解

摘要&#xff1a;近年來&#xff0c;基于視頻的多模態大型語言模型&#xff08;Video-LLMs&#xff09;通過將視頻處理為圖像幀序列&#xff0c;顯著提升了視頻理解能力。然而&#xff0c;許多現有方法在視覺主干網絡中獨立處理各幀&#xff0c;缺乏顯式的時序建模&#xff0c;…

無障礙閱讀(Web Accessibility)NVDA打開朗讀查看器后,enter鍵不生效的原因

用NVDA測試Web Accessibility時&#xff0c;打開朗讀查看器&#xff0c;enter鍵會無效&#xff0c;而不打開測試器&#xff0c;就沒有問題&#xff0c;很大原因是被應用的元素不是可聚焦的&#xff0c;解決方法嘗試&#xff1a; 將標簽改為可聚焦的語義化標簽&#xff0c;如 b…

2Android中的AIDL是什么以及如何使用它

一、Android中的AIDL概述 AIDL&#xff08;Android Interface Definition Language&#xff09;是Android系統中用于定義和實現跨進程通信&#xff08;IPC&#xff09;接口的語言。它允許一個進程向另一個進程發送請求并獲取響應&#xff0c;是Android中實現進程間通信的一種重…

Python繪制數據分析中經典的圖形--列線圖

Python繪制數據分析中經典的圖形–列線圖 列線圖是數據分析中的經典圖形&#xff0c;通過背后精妙的算法設計&#xff0c;展示線性模型&#xff08;logistic regression 和Cox&#xff09;中各個變量對于預測結果的總體貢獻&#xff08;線段長短&#xff09;&#xff0c;另外&…

leetcode【面試經典150系列】(一)

目錄 121.買賣股票最佳時機 題目描述 示例 算法分析 代碼(python3) 122.買賣股票最佳時機II 題目描述 示例 算法分析 代碼&#xff08;python3&#xff09; 55.跳躍游戲 題目描述 示例 算法分析 代碼 45.跳躍游戲II 題目描述 示例 算法分析 代碼 121.買賣股票…

為什么會出現redis數據庫?redis是什么?

什么是 Redis? 為什么要用 Redis? 下面我將從 Redis 出現的背景、Redis 的解決方案個來回答。 1、Redis 出現的背景 互聯網的應用越來越多&#xff0c;例如社交網絡、電商、實時服務發展的十分迅速&#xff0c;這就導致了傳統技術棧&#xff08;如關系型數據庫&#xff09;…

Windows 11下Git Bash執行cURL腳本400問題、CMD/PowerShell不能執行多行文本等問題記錄及解決方案

問題 在Postman里可成功執行的POST請求&#xff1a; 找到Postman的Code 因為cURL基本上算是行業標準&#xff0c;所以Postman默認選中cURL&#xff0c;支持切換不同的開發語言&#xff1a; 點擊上圖右上角的復制按鈕&#xff0c;得到cURL腳本。 Windows 11家庭版&#xff…

Docker基礎入門(一)

初識Docker 什么是Docker Docker是一個快速交付應用、運行應用的技術&#xff1a; 可以將程序及其依賴、運行環境一起打包為一個鏡像&#xff0c;可以遷移到任意Linux操作系統運行時利用沙箱機制形成隔離容器&#xff0c;各個應用互不干擾啟動、移除都可以通過一行命令完成&…

容器編排革命:從 Docker Run 到 Docker Compose 的進化之路20250309

容器編排革命&#xff1a;從 Docker Run 到 Docker Compose 的進化之路 一、容器化部署的范式轉變 在 Docker 生態系統的演進中&#xff0c;容器編排正從“手動操作”走向“自動化管理”。根據 Docker 官方 2023 年開發者調查報告&#xff0c;78% 的開發者已采用 Docker Compo…

c++ 嵌入匯編的方式實現int型自增

x86/x86_64 實現 x86 平臺上&#xff0c;使用 LOCK XADD 指令來實現原子自增&#xff1a; #include <iostream>inline int atomic_increment_x86(int* value) {int result;__asm__ __volatile__("lock xaddl %1, %0": "m"(*value), "r"(…

區塊鏈與去中心化技術

區塊鏈與去中心化技術 核心進展 區塊鏈從加密貨幣&#xff08;如比特幣&#xff09;擴展至智能合約和供應鏈管理。以太坊2.0引入分片技術提升交易吞吐量&#xff0c;而零知識證明&#xff08;ZKP&#xff09;增強了隱私保護15。企業級應用如IBM的Food Trust平臺通過區塊鏈追蹤…

逐夢DBA:Linux環境下 MySQL 的卸載

1. 查看是否安裝過MySQL&#xff0c;如果不存在&#xff0c;則不顯示任何內容 rpm -qa | grep -i mysql # -i 忽略大小寫 2. 查看MySQL服務狀態 systemctl status mysqld.service 3. 關閉 mysql 服務 systemctl stop mysqld.service 4. 查看當前 mysql 卸載狀況 rpm -qa…

【藍橋杯python研究生組備賽】003 貪心

題目1 股票買賣 給定一個長度為 N 的數組&#xff0c;數組中的第 i 個數字表示一個給定股票在第 i 天的價格。 設計一個算法來計算你所能獲取的最大利潤。你可以盡可能地完成更多的交易&#xff08;多次買賣一支股票&#xff09;。 注意&#xff1a;你不能同時參與多筆交易&…

網絡通信Socket中多態HandleIO設計模式深度解析

網絡通信 Socket 中多態 handleIO 詳細講解 大綱 引言 網絡通信的重要性Socket 編程在網絡通信中的地位多態 handleIO 的意義和作用 Socket 編程基礎 Socket 的基本概念Socket 的類型&#xff08;TCP 和 UDP&#xff09;Socket 編程的基本流程 多態的概念與實現 多態的定義和…

flutter 如何與原生框架通訊安卓 和 ios

在 Flutter 中與原生框架&#xff08;Android 和 iOS&#xff09;進行通信的主要方式是通過 **平臺通道&#xff08;Platform Channels&#xff09;**。平臺通道允許 Flutter 代碼與原生代碼進行雙向通信。以下是詳細的步驟和示例&#xff0c;說明如何在 Flutter 中與 Android …

LabVIEW VI Scripting實現連接器窗格自動化

通過VI Scripting自動化配置連接器窗格&#xff0c;可大幅提升開發效率、統一接口規范&#xff0c;并適配動態需求。以下為真實場景中的典型應用案例&#xff0c;涵蓋工業、汽車電子及教育領域&#xff0c;展示其實際價值與實施效果。 特點&#xff1a; 程序化配置&#xff1a;…

1-001:MySQL的存儲引擎有哪些?它們之間有什么區別?

MySQL 存儲引擎 ├── InnoDB&#xff08;默認引擎&#xff09; │ ├── 事務支持&#xff1a;支持 ACID 和事務&#xff08;事務日志、回滾、崩潰恢復&#xff09; │ ├── 鎖機制&#xff1a;支持行級鎖&#xff0c;提高并發性能 │ ├── 外鍵支持&#xff1a;支持外鍵…

package.json 依賴包約束及快速刪除node_modules

文章目錄 一、package.json版本約束1、初始項目安裝2. 已有 yarn.lock 文件的項目安裝3. 特殊情況手動修改 package.json 版本&#xff1a;使用 yarn upgrade 命令&#xff1a; 二、快速刪除node_modules三、depcheck 檢測npm未使用的依賴 一、package.json版本約束 1、初始項…