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

LearnOpenGL02:绘制三角形和矩形

必读

Hello Triangle:了解整体的渲染流程以及相关概念

概念

  • 顶点数组对象:Vertex Array Object,VAO
  • 顶点缓冲对象:Vertex Buffer Object,VBO
  • 元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO

测试代码

修改cmake支持多个程序,方便调试

cmake_minimum_required(VERSION 3.24)
project(MultiGL)set(CMAKE_CXX_STANDARD 14)include_directories(include)# 查找GLFW库
find_package(PkgConfig REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)# include_directories和add_executable可以二选一
add_executable(OGLTestsrc/part1/main.cpp src/glad.c)
target_link_libraries(OGLTest ${GLFW_LIBRARIES})add_executable(HelloTrianglesrc/part2/hellotriangle.cpp src/glad.c)
target_link_libraries(HelloTriangle ${GLFW_LIBRARIES})add_executable(HelloTriangleIndexedsrc/part2/hellotriangleindex.cpp src/glad.c)
target_link_libraries(HelloTriangleIndexed ${GLFW_LIBRARIES})

程序1:绘制一个三角形

  1. 自定义定点着色器vertex shader
  2. 自定义片段着色器fragment shader
  3. 创建shader program并链接shaders
  4. 设置VBO和VAO
  5. 绑定VBO到VAO
  6. 设置vertex Attributes
  7. 实际绘图
//
// Created by aft on 2025/5/12.
//
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;const char *vertexShaderSource = "#version 330 core\n""layout (location = 0) in vec3 aPos;\n""void main()\n""{\n""   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n""}\0";
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";// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// make sure the viewport matches the new window dimensions; note that width and// height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height);
}void processInput(GLFWwindow *window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}int main() {// 初始化GLFW库glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建windowGLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "HelloTriangle", NULL, NULL);if (window == nullptr) {std::cout << "Failed to create window" << std::endl;glfwTerminate();return -1;}// 将window的context绑定到当前线程(必须)glfwMakeContextCurrent(window);// 设置窗口变化时的回调glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 初始化OGL函数指针表,将所有OGL的函数地址加载到GLAD的内部结构中if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress))) {std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// --------------重点-------------// 构建和编译我们的shader着色器// ----------------------------------------// 定点着色器 vertex shaderunsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);int success{0};char infoLog[512];// 检查vertexShader是否编译成功glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// 片段着色器 fragment shaderunsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// 检查fragmentShader是否编译成功glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// 链接shadersunsigned int shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// 检查program是否链接成功glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}// 链接成功后就能删除原来的shader对象了,因为已经拷贝到program里面去了,想象一下代码编译后,源代码可以删除了glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// 设置顶点数据和设置定点属性// ---------------------------float vertices[] = {-0.5f, -0.5f, 0.0f, // left0.5f, -0.5f, 0.0f, // right0.0f,  0.5f, 0.0f  // top};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// 先绑定Vertex Array Object,再绑定和设置Vertex Buffer(s),然后再配置Vertex AttributesglBindVertexArray(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);// 开启读取索引为0的VAO的数据glEnableVertexAttribArray(0);// 解除VBO和VAO的绑定glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);while (!glfwWindowShouldClose(window)) {processInput(window);// 清理画面颜色glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 绘制第一个三角形glUseProgram(shaderProgram);glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);// 交换数据glfwSwapBuffers(window);glfwPollEvents();}// 资源回收glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);glfwTerminate();return 0;
}

程序2:绘制一个矩形

可以按照程序1的方式连续绘制两个三角形,但是比较繁琐
使用元素缓冲对象(Element Buffer Object,EBO),通过索引绘制的方式减少浪费
与程序1的差别主要体现在使用了4个顶点,然后通过索引的方式绘制

//
// Created by aft on 2025/5/12.
//
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;const char *vertexShaderSource = "#version 330 core\n""layout (location = 0) in vec3 aPos;\n""void main()\n""{\n""   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n""}\0";
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";// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{// make sure the viewport matches the new window dimensions; note that width and// height will be significantly larger than specified on retina displays.glViewport(0, 0, width, height);
}void processInput(GLFWwindow *window)
{if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)glfwSetWindowShouldClose(window, true);
}int main() {// 初始化GLFW库glfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建windowGLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "HelloTriangle", NULL, NULL);if (window == nullptr) {std::cout << "Failed to create window" << std::endl;glfwTerminate();return -1;}// 将window的context绑定到当前线程(必须)glfwMakeContextCurrent(window);// 设置窗口变化时的回调glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 初始化OGL函数指针表,将所有OGL的函数地址加载到GLAD的内部结构中if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress))) {std::cout << "Failed to initialize GLAD" << std::endl;return -1;}// --------------重点-------------// 构建和编译我们的shader着色器// ----------------------------------------// 定点着色器 vertex shaderunsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);glCompileShader(vertexShader);int success{0};char infoLog[512];// 检查vertexShader是否编译成功glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// 片段着色器 fragment shaderunsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);glCompileShader(fragmentShader);// 检查fragmentShader是否编译成功glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);if (!success) {glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;}// 链接shadersunsigned int shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);// 检查program是否链接成功glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;}// 链接成功后就能删除原来的shader对象了,因为已经拷贝到program里面去了,想象一下代码编译后,源代码可以删除了glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// 设置顶点数据和设置定点属性  增加元素缓冲对象Element Buffer Object EBO// ---------------------------float vertices[] = {0.5f,  0.5f, 0.0f,  // top right0.5f, -0.5f, 0.0f,  // bottom right-0.5f, -0.5f, 0.0f,  // bottom left-0.5f,  0.5f, 0.0f   // top left};unsigned int indices[] = {0, 1, 3,  // first Triangle1, 2, 3   // second Triangle};unsigned int VBO, VAO, EBO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glGenBuffers(1, &EBO);// 先绑定Vertex Array Object,再绑定和设置Vertex Buffer(s),然后再配置Vertex AttributesglBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 绑定EBOglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);// 开启读取索引为0的VAO的数据glEnableVertexAttribArray(0);// 解除VBO和VAO的绑定glBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);while (!glfwWindowShouldClose(window)) {processInput(window);// 清理画面颜色glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 绘制第一个三角形glUseProgram(shaderProgram);glBindVertexArray(VAO);
//        glDrawArrays(GL_TRIANGLES, 0, 3);// 替换成下面函数进行绘图glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);// 交换数据glfwSwapBuffers(window);glfwPollEvents();}// 资源回收glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteProgram(shaderProgram);glfwTerminate();return 0;
}

相关文章:

  • 【办公类-99-06】20250512用Python制作PPT的GIF照片动图(统一图片大小、自定义不同切换秒数,以蝴蝶为例)
  • 家具制造行业的现状 质检LIMS如何赋能家具制造企业质检升级
  • 学习黑客5 分钟深入浅出理解系列之 Windows 资源监视器
  • LeetCode 热题 100_只出现一次的数字(96_136_简单_C++)(哈希表;哈希集合;排序+遍历;位运算)
  • Windows 安装 Milvus
  • 基于ESP32的健康智能机器人
  • 使用conda导致无法找到libpython动态库
  • 高粘度、强腐蚀介质解决方案:V型气动带手动活塞式开关调节球阀的五大核心优势-耀圣控制
  • react项目阅读记录
  • 做为一个平台,给第三方提供接口的时候,除了要求让他们申请 appId 和 AppSecret 之外,还应当有哪些安全选项,要过等保3级
  • 加固python文件
  • 用短说社区搭建的沉浸式生活方式分享平台
  • MyBatis-Plus使用 wrapper.apply() 添加自定义 SQL 片段
  • 多线程下的事务失效及解决形式
  • NVMe-oF(NVMe over Fabrics)
  • 图灵爬虫练习平台第九题js逆向
  • 计网学习笔记———通信知识(计算机网络通信单独讲)
  • Flask支持哪些日志框架
  • LC滤波器与电感、电容的区别:技术分析与应用
  • 手机电池健康提示怎么看?
  • 长沙查处疑似非法代孕:有人企图跳窗,有女子被麻醉躺手术台
  • 石家庄推动城市能级与民生福祉并进
  • 今起公开发售,宁德时代将于5月20日在港股上市
  • 中美会谈前都发生了什么?美方为何坐不住了?
  • 山西忻州市人大常委会副主任郭建平接受审查调查
  • 上海“量子城市”先导应用场景落地曹杨社区,提供哪些服务?