OpenGL入门

一、环境搭建

  1. 库依赖安装
    需要安装GLFW(窗口管理)和GLAD(函数指针加载库)。在Windows下推荐使用Visual Studio的vcpkg包管理工具进行安装,Linux下通过apt-get安装相关依赖‌。

  2. 窗口初始化
    使用GLFW创建窗口并绑定OpenGL上下文,核心代码如下:

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // OpenGL 3.3核心模式
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
    glfwMakeContextCurrent(window); // 绑定当前线程上下文‌

二、核心对象理解

  1. VBO(Vertex Buffer Object)
    用于存储顶点数据(坐标、颜色等)的显存对象,通过glBindBuffer(GL_ARRAY_BUFFER, VBO)绑定数据到GPU‌。

  2. VAO(Vertex Array Object)
    管理顶点属性指针配置的容器,简化顶点数据格式的切换。VAO记录当前绑定的VBO和属性指针状态‌。

  3. EBO(Element Buffer Object)
    存储顶点索引数据,实现顶点复用,减少重复数据占用显存‌。

三、渲染管线基础

  1. 顶点着色器(Vertex Shader)
    处理顶点坐标变换,例如MVP(模型-视图-投影)矩阵运算,输出裁剪空间坐标‌。

  2. 片段着色器(Fragment Shader)
    决定像素颜色,支持光照计算、纹理采样等操作‌。

  3. 着色器编译
    通过glCreateShaderglShaderSource加载GLSL代码,glCompileShader验证语法正确性‌。

四、绘制流程

OpenGL 现代核心模式(Core Profile)的标准绘制流程,分为 ‌初始化阶段‌ 和 ‌渲染循环阶段‌:

1、初始化阶段(一次性操作)

1. ‌顶点数据准备
// 定义顶点数据(包含坐标、颜色、纹理坐标等)
float vertices[] = {// 位置             // 颜色           // 纹理坐标-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,  // 左下0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,  // 右下0.0f,  0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f   // 顶部
};
2. ‌创建缓冲对象
// 生成 VAO/VBO/EBO
unsigned int VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO); // 可选(用于索引绘制)// 绑定 VAO
glBindVertexArray(VAO);// 将顶点数据复制到 VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 将索引数据复制到 EBO(如果有)
unsigned int indices[] = {0, 1, 2};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
3. ‌配置顶点属性指针
// 位置属性(属性位置 0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);// 颜色属性(属性位置 1)
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);// 纹理坐标属性(属性位置 2)
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
4. ‌着色器编译与链接
// 创建着色器程序
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader); // 检查编译错误unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader); // 检查编译错误// 链接着色器程序
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram); // 检查链接错误

2、渲染循环阶段(每帧执行)

1. ‌清空缓冲区
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 设置清屏颜色
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色和深度缓冲
2. ‌绑定资源
glUseProgram(shaderProgram);     // 激活着色器程序
glBindVertexArray(VAO);          // 绑定顶点数组对象// 绑定纹理(如果有)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(glGetUniformLocation(shaderProgram, "textureSampler"), 0);
3. ‌绘制指令
// 方式一:直接绘制三角形
glDrawArrays(GL_TRIANGLES, 0, 3);// 方式二:使用索引绘制(需提前绑定 EBO)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
4. ‌交换缓冲区和处理事件
glfwSwapBuffers(window); // 双缓冲切换(避免画面撕裂)
glfwPollEvents();        // 处理键盘/鼠标输入等事件

五、入门代码

绘制第一个三角形 

// 初始化 GLFW 和窗口 ‌:ml-citation{ref="4,6" data="citationList"}
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);// 顶点数据定义
float vertices[] = {-0.5f, -0.5f, 0.0f,  // 左下角0.5f, -0.5f, 0.0f,  // 右下角0.0f,  0.5f, 0.0f   // 顶部
};// 创建缓冲对象
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 配置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);// 顶点着色器代码
const char* vertexShaderSource = "#version 330 core\n""layout (location=0) in vec3 aPos;\n""void main() { gl_Position = vec4(aPos, 1.0); }";// 渲染循环
while (!glfwWindowShouldClose(window)) {glClear(GL_COLOR_BUFFER_BIT);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);glfwSwapBuffers(window);
}

六、Qt 中集成 OpenGL

在 Qt 中集成 OpenGL 主要依赖 QOpenGLWidget 和 QOpenGLFunctions 等核心组件。

  1. QOpenGLWidget

    • 替代旧版 QGLWidget,支持 Qt5/Qt6,提供以下虚函数实现 OpenGL 渲染流程‌:
      • initializeGL():初始化 OpenGL 资源和状态(如着色器、缓冲区等)。
      • resizeGL():调整视口和投影矩阵,响应窗口尺寸变化。设置OpenGL的viewport、投影projection等。每当widget调整大小时调用。
      • paintGL():执行实际的渲染操作,如绘制几何图形或点云。每当需要更新widget时调用。
    • 支持与 Qt 控件(如按钮、布局)无缝集成,适合构建复杂的图形界面‌。
  2. 着色器与程序管理

    • 使用 QOpenGLShader 和 QOpenGLShaderProgram 管理顶点/片段着色器,通过 GLSL 编写图形处理逻辑‌。

Qt 中使用 QOpenGLWidget 实现基础 3D 图形渲染的实例代码,包含纹理贴图和平移变换功能。 

// 头文件 GLWidget.h
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Core {
public:explicit GLWidget(QWidget *parent = nullptr): QOpenGLWidget(parent){};~GLWidget(){};protected:void initializeGL() override;  void paintGL() override;       void resizeGL(int w, int h) override; private:QOpenGLShaderProgram m_program;  QOpenGLTexture *m_texture;GLuint VAO, VBO; QMatrix4x4 m_modelMatrix; 
};// 实现文件 GLWidget.cpp
void GLWidget::initializeGL() {initializeOpenGLFunctions();  glClearColor(0.2f, 0.3f, 0.3f, 1.0f);// 编译着色器m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, "#version 450 core\n""layout (location=0) in vec3 aPos;\n""layout (location=1) in vec2 aTexCoord;\n""out vec2 TexCoord;\n""uniform mat4 model;\n""void main() {\n""  gl_Position = model * vec4(aPos, 1.0);\n""  TexCoord = aTexCoord;\n""}"); m_program.addShaderFromSourceCode(QOpenGLShader::Fragment,"#version 450 core\n""in vec2 TexCoord;\n""out vec4 FragColor;\n""uniform sampler2D texture1;\n""void main() {\n""  FragColor = texture(texture1, TexCoord);\n""}");m_program.link(); // 顶点数据(包含位置和纹理坐标)float vertices[] = {// positions       // texture coords-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.0f,  0.5f, 0.0f, 0.5f, 1.0f};// 创建VBO和VAOglGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 设置顶点属性指针glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(3*sizeof(float)));glEnableVertexAttribArray(1); // 加载纹理m_texture = new QOpenGLTexture(QImage(":/textures/wood.png").mirrored()); m_texture->setWrapMode(QOpenGLTexture::Repeat); m_texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
}void GLWidget::paintGL() {glClear(GL_COLOR_BUFFER_BIT);m_program.bind(); // 设置模型矩阵(平移变换)m_modelMatrix.setToIdentity();m_modelMatrix.translate(0.5f, 0.0f, 0.0f); m_program.setUniformValue("model", m_modelMatrix); // 绑定纹理m_texture->bind(0); m_program.setUniformValue("texture1", 0); // 绘制三角形glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 3);m_program.release();
}void GLWidget::resizeGL(int w, int h) {glViewport(0, 0, w, h); 
}

关键实现说明:

  1. OpenGL上下文初始化
    通过 initializeOpenGLFunctions() 加载 OpenGL 函数指针‌,使用 QOpenGLShaderProgram 管理着色器程序‌。

  2. 纹理处理流程
    使用 QOpenGLTexture 加载图片并设置环绕/过滤参数‌,通过 texture() 函数在片段着色器采样纹理‌。

  3. 矩阵变换实现
    通过 QMatrix4x4 实现模型矩阵的平移操作,并传递至着色器‌。

  4. 顶点数据管理
    使用 VAO/VBO 封装顶点属性(位置、纹理坐标)‌,通过 glVertexAttribPointer 指定数据布局‌。

  5. 调试技巧
    使用以下函数检查错误:

    GLenum err = glGetError(); // 返回 GL_NO_ERROR 表示无错误
  6. 多线程渲染

    • 创建独立的渲染线程,通过QOpenGLContextQOffscreenSurface在子线程中完成OpenGL渲染,将结果绑定到纹理或QImage后传递给主线程显示‌。

    • 需通过信号槽或条件变量控制渲染线程与UI线程的同步,避免上下文竞争‌。

    • 每个线程需拥有独立的QOpenGLContext,且上下文必须在目标线程内创建和激活‌。使用QOpenGLContext::makeCurrent()doneCurrent()显式控制上下文所有权切换‌。‌

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39378.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JVM(基础篇)

一.初识JVM 1.什么是JVM JVM全称Java Virtyal Machine&#xff0c;中文译名 Java虚拟机 。JVM本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件(将字节码解释成机器码)。 2.JVM的功能 解释和运行&#xff1a;对字节码文件中的指令号&#xff0c;实时…

VMware安装ubuntu22.04.5 server

下载Ubuntu镜像 https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/22.04.5/ 安装系统 打开vmware 点击创建新的虚拟机 选择自定义 点击下一步 选择稍后安装操作系统&#xff0c;点击下一步 选择Linux系统&#xff0c;选择ubuntu64&#xff0c;点击下一步 选择安装位置&…

Docker容器之Dockerfile

用来构建镜像的文件。是指就是命令&#xff0c;参数&#xff0c;脚本。 指令合集以及说明 构建镜像图解: 实战测试&#xff1a; 构建自己的ubuntu&#xff1a; FROM ubuntu MAINTAINER liux ENV MYPATH /usr/local WORKDIR $MYPATH RUN apt-get update RUN apt install net-…

STM32G030移植RT-Thread

移植流程 移植前需要安装Keil.STM32G0xx_DFP.1.2.0.pack组件&#xff0c;大致的移植过程&#xff1a; CubeMX配置RT-Thread组件配置工程模板配置 参考例程配置&#xff1a;拷贝仓库原有的stm32g070-st-nucleo工程&#xff0c;然后另起一个名字&#xff0c;目录结构如下 完整…

【网络】网关

【网络】网关 网关 是计算机网络中用于连接两个不同网络的设备或服务器&#xff0c;它充当着“翻译器”和“转发器”的角色&#xff0c;将数据包从一个网络传递到另一个网络&#xff0c;并在必要时进行协议转换和数据重包装。 主要功能 数据转发&#xff1a;当本地网络设备发…

用JS+Promise实现简单消息队列

一、什么是消息队列 消息队列是一种用于在软件系统之间传递消息的技术。它常被用于解耦不同组件或模块之间的通信&#xff0c;减少系统中各个部分之间的直接依赖关系。消息队列可以实现异步通信&#xff0c;发送方将消息发送到队列中&#xff0c;接收方从队列中获取消息并进行处…

【Python爬虫】使用python脚本拉取汽车网站品牌数据

示例代码说明&#xff1a; 在汽车之家网站拉取当月排行榜中汽车品牌、销量和价格信息&#xff0c;存为csv文档输出&#xff0c;使用正则表达式获取网页内容 import re import pandas as pd import requests# 汽车之家车型列表页URL url https://cars.app.autohome.com.cn/ca…

批量修改 PPT 文档中主题、编辑时长、来源等元数据信息

每一个 PPT 文档被创建之后&#xff0c;都会包含一些元数据信息。这些元数据信息记录着文件的作者、创建时间、修改时间、打印时间等信息。这些信息默认都是自动生成的&#xff0c;如果我们想要对这些元数据进行修改&#xff0c;当然也是可以的。今天就给大家介绍一下如何批量修…

丐版插入selectdb模拟

为了模拟不断插入数据到库里&#xff0c;写个简单的循环脚本 #!/bin/bash #计算时差 function getTiming(){start$1end$2start_secho $start | cut -d . -f 1start_nsecho $start | cut -d . -f 2end_secho $end | cut -d . -f 1end_nsecho $end | cut -d . -f 2time_micro$((…

Off-Road-Freespace-Detection配置pytorch2.0.0

一、概述 在github上进行开源代码搜索&#xff0c;发现了Off-Road-Freespace-Detection&#xff08;链接如下所示&#xff09;。这是对越野环境可通行区域的检测&#xff0c;在经过测试之后&#xff0c;发现对自己有益。 GitHub - chaytonmin/Off-Road-Freespace-Detection: O…

常见中间件漏洞之四:Apache

1. CVE-2021-41773 Apache HTTP Server 路径穿越漏洞 漏洞简介 该漏洞是由于Apache HTTP Server 2.4.49版本存在⽬录穿越漏洞,在路径穿越⽬录<Directory/>Require all granted</Directory>允许被访问的的情况下&#xff08;默认开启&#xff09;&#xff0c;攻击…

Pytorch中Tensorboard的学习

1、Tensorboard介绍 TensorBoard 是 TensorFlow 开发的一个可视化工具&#xff0c;用于帮助用户理解和调试机器学习模型的训练过程。尽管它最初是为 TensorFlow 设计的&#xff0c;但通过 PyTorch 的 torch.utils.tensorboard 模块&#xff0c;PyTorch 用户也可以方便地使用 Te…

刷机维修进阶教程-----adb禁用错了系统app导致无法开机 如何保数据无损恢复机型

在刷机维修过程中 。我们会遇到一些由于客户使用adb指令来禁用手机app而导致手机无法开机进入系统的故障机型。通常此类问题机型有好几种解决方法。但如果客户需要保数据来恢复机型。其实操作也是很简单的.还有类似误删除应用导致不开机等等如何保数据。 通过博文了解💝💝�…

哪吒汽车:一边熬夜蹦迪,一边找药投医

两年前&#xff0c;威马CEO沈晖发了个短视频&#xff0c;内容是“活下去&#xff0c;像牲口一样活下去”。 如今最能体会沈晖当时心情的&#xff0c;估计就是方运舟了。 作为哪吒汽车创始人兼董事长&#xff0c;他连续多次被限高&#xff0c;为了让哪吒汽车活下去&#xff0c…

2025 cs144 Lab Checkpoint 1小白超详细版

cs144官网&#xff1a;https://cs144.github.io/ 我的github&#xff1a;https://github.com/Albert-tru/cs144-2025 文章目录 1 手动发送internet数据报协议号5、7&#xff1f;思路&#xff1f; 2 实现一个Reassembler类2.1 几个帮助理解代码的Q&AQ1&#xff1a;insert的参…

使用 OpenCV 拼接进行图像处理对比:以形态学操作为例

图像处理在计算机视觉中起着至关重要的作用&#xff0c;而 OpenCV 作为一个强大的图像处理库&#xff0c;提供了丰富的函数来实现各类图像处理任务。形态学操作&#xff08;Morphological Operations&#xff09;是其中常用的技术&#xff0c;尤其适用于二值图像的处理。常见的…

单链表的查找和插入,删除操作

1.单链表的查找 snode* slistfind(snode* stlheap, stltype x) {while (stlheap){if (stlheap->data x){return stlheap;}stlheap stlheap->next;}return NULL; } 2.单链表的插入操作 2.1在指定位置之前插入节点 void slistinsert(snode** stlheap, snode* pos, stl…

一文速通Python并行计算:00 并行计算的基本概念

一文速通 Python 并行计算&#xff1a;00 并行计算的基本概念 摘要&#xff1a; 该文介绍了 Python 并行计算的核心概念、编程模型及其应用&#xff0c;并介绍了了并行程序的性能分析与优化方法&#xff0c;如并行效率、加速比及 Amdahl 定律。此外&#xff0c;该文介绍了共享…

vue中keep-alive组件的使用

keep-alive是vue的内置组件&#xff0c;它的主要作用是对组件进行缓存&#xff0c;避免组件在切换时被重复创建和销毁&#xff0c;从而提高应用的性能和用户体验。它自身不会渲染一个 DOM 元素&#xff0c;也不会出现在父组件链中。使用时&#xff0c;只需要将需要缓存的组件包…

Python Excel表格数据对比工具

【Excel对比工具】提升工作效率的神奇助手&#xff1a;基于PyQt5和Pandas的文件数据对比应用 相关资源文件已经打包成EXE文件&#xff0c;可双击直接运行程序&#xff0c;且文章末尾已附上相关源码&#xff0c;以供大家学习交流&#xff0c;博主主页还有更多Python相关程序案例…