当前位置: 首页 > backend >正文

【OpenGL学习】(三)元素缓冲对象(EBO)的使用

【OpenGL学习】(三)元素缓冲对象的使用

float vertices[] = {// 第一个三角形0.5f, 0.5f, 0.0f,   // 右上角0.5f, -0.5f, 0.0f,  // 右下角-0.5f, 0.5f, 0.0f,  // 左上角// 第二个三角形0.5f, -0.5f, 0.0f,  // 右下角(重复)-0.5f, -0.5f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f   // 左上角(重复)
};

现在我们需要渲染这两个三角形,但它们包含重复的顶点,导致内存的浪费。通过使用索引来组合这些顶点,我们可以复用重复的顶点,从而节省内存。

	// 使用vertices中的第0,1,3个顶点绘制第一个三角形  // 使用vertices中的第1,2,3个顶点绘制第二个三角形float vertices[] = {0.5f, 0.5f, 0.0f,   // 右上角0.5f, -0.5f, 0.0f,  // 右下角-0.5f, -0.5f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f   // 左上角};

这可以通过元素缓冲对象(EBO)实现:

以下代码对【OpenGL学习】(二)OpenGL渲染简单图形中的代码进行进行修改(修改内容用!标记)

// https://github.com/JoeyDeVries/LearnOpenGL/tree/master/src/1.getting_started/2.2.hello_triangle_indexed
#include <glad/glad.h>  // 加载 OpenGL 函数指针
#include <GLFW/glfw3.h> // GLFW 用于创建窗口和处理输入#include <iostream>     // 回调函数声明:当窗口大小发生改变时调用
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
// 处理输入的函数声明
void processInput(GLFWwindow* window);// 设置窗口宽高
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;// 顶点着色器GLSL源码
const char* vertexShaderSource = "#version 330 core\n" // 使用 OpenGL 3.3 对应的 GLSL 版本(即 GLSL 3.30)
"layout (location = 0) in vec3 aPos;\n"  // 顶点位置属性,位置值为0
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"  // 设置顶点位置
"}\0";// 片段着色器GLSL源码
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"  // 片段输出颜色
"void main()\n"
"{\n"
"   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"  // 设置输出颜色为橙色
"}\n\0";int main()
{// 初始化并配置 GLFWglfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // OpenGL 主版本号glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // OpenGL 次版本号glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 使用核心模式#ifdef __APPLE__glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // MacOS 需要加这句
#endif// 创建 GLFW 窗口GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate(); // 初始化失败,退出程序return -1;}glfwMakeContextCurrent(window); // 将窗口上下文设为当前线程上下文glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // 设置窗口大小改变时的回调// 初始化 GLAD,用于加载 OpenGL 函数if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// ------------------构建并编译着色器程序------------------// 顶点着色器unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); // 创建着色器对象glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);   // 附加源码glCompileShader(vertexShader);                                // 编译着色器// 检查编译错误int success;char infoLog[512];glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// 片段着色器unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);// 创建一个片段着色器对象glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); // 将片段着色器源码附加到着色器对象上glCompileShader(fragmentShader);   // 编译片段着色器源码// 检查编译错误glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success){glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;}// 着色器程序unsigned int shaderProgram = glCreateProgram();           // 创建程序对象glAttachShader(shaderProgram, vertexShader);              // 附加着色器glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);                             // 链接程序// 检查链接错误glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}// 删除已编译的着色器对象,已链接到程序中不再需要glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// --------------------------------------------------------//  !设置顶点数据和缓冲,并配置顶点属性 float vertices[] = {0.5f, 0.5f, 0.0f,   // 右上角0.5f, -0.5f, 0.0f,  // 右下角-0.5f, -0.5f, 0.0f, // 左下角-0.5f, 0.5f, 0.0f   // 左上角};//  索引!unsigned int indices[] = {0, 1, 3, // 使用vertices中的第0,1,3个顶点绘制第一个三角形  1, 2, 3  // 使用vertices中的第1,2,3个顶点绘制第二个三角形};unsigned int VBO, VAO, EBO;  // !glGenVertexArrays(1, &VAO); // 创建顶点数组对象glGenBuffers(1, &VBO);      // 创建顶点缓冲对象glGenBuffers(1, &EBO);       // ! 创建元素缓冲对象glBindVertexArray(VAO);     // 绑定 VAOglBindBuffer(GL_ARRAY_BUFFER, VBO); // 绑定 VBO glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // !绑定 EBO glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 传入数据glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); //! 传入索引// 设置顶点属性指针glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0); // 启用顶点属性// !当 VAO 处于活动状态时,不要解绑 EBO”,是因为解绑会改变 VAO 记录的 EBO 绑定,导致后续绘制失效//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);glBindBuffer(GL_ARRAY_BUFFER, 0); // 解绑 VBO,为了安全,非必须glBindVertexArray(0);            // 解绑 VAO// 可以取消注释以使用线框模式绘制:也就是不填充图形,只画出边框线glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);// 渲染循环while (!glfwWindowShouldClose(window)){// 处理输入processInput(window);// 清屏并设置背景颜色glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 绘制三角形glUseProgram(shaderProgram); // 使用着色器程序glBindVertexArray(VAO);      // 绑定 VAO//glDrawArrays(GL_TRIANGLES, 0, 6);glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // !// 交换缓冲区并查询IO事件glfwSwapBuffers(window);glfwPollEvents();}// 可选:释放所有资源glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);// 释放 GLFW 资源glfwTerminate();return 0;
}// 处理输入:如果按下 ESC 键,则关闭窗口
void processInput(GLFWwindow* window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}// 当窗口大小发生改变时,自动调整视口大小
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height); // 设置 OpenGL 视口大小
}

行进行修改(修改内容用!标记)
在这里插入图片描述

http://www.xdnf.cn/news/7043.html

相关文章:

  • Limesurvay系统“48核心92GB服务器”优化方案
  • uniapp的适配方式
  • PDF批量合并拆分+加水印转换 编辑 加密 OCR 识别
  • 软件架构之-论软件系统架构评估以及应用
  • Zookeeper入门(三)
  • 《Vite 报错》ReferenceError: module is not defined in ES module scope
  • 影刀处理 Excel:智能工具带来的高效变革
  • 广域网学习
  • 数据结构与算法——栈和队列
  • Python字符串格式化(一):三种经典格式化方法
  • 从零开始实现大语言模型(十六):加载开源大语言模型参数
  • 《Python星球日记》 第87天:什么是大语言模型 LLM?
  • 1_Spring 【IOC容器的创建】
  • 深入了解linux系统—— 基础IO(下)
  • 【QGIS二次开发】地图编辑-08
  • tauri2项目使用sidcar嵌入可执行文件并使用命令行调用
  • 实战设计模式之状态模式
  • 互联网大厂Java面试场景:从Spring Boot到分布式缓存技术的探讨
  • 十一、STM32入门学习之FREERTOS移植
  • React 19 中的useRef得到了进一步加强。
  • ngx_http_proxy_protocol_vendor_module 模块
  • 【Linux】进程的基本概念
  • 虚幻引擎5-Unreal Engine笔记之Pawn与胶囊体的关系
  • 【android bluetooth 协议分析 01】【HCI 层介绍 5】【SetEventMask命令介绍】
  • Elasticsearch 初步认识
  • 用 UniApp 构建习惯打卡 App —— HabitLoop 开发记
  • 【cursor】有效解决
  • Denoising Score Matching with Langevin Dynamics
  • 【HarmonyOS 5开发入门】DevEco Studio安装配置完全指南
  • Flink 的窗口机制