OpengGL教程(四)---使用EBO方式绘制矩形

本章参考官方教程:learnopengl-cn

本系列历史文
OpengGL教程(一)—OpenGL环境的配置(GLFW3,GLAD)
OpengGL教程(二)—渲染一个简单的窗体
OpengGL教程(三)—使用VAO和VBO方式绘制三角形

本章的GLSL不需要改变参考第三章中的VertexShader.glslFragmentShader.glsl即可

顶点数组对象:Vertex Array Object, 		VAO
顶点缓冲对象:Vertex Buffer Object,		VBO
元素缓冲对象:Element Buffer Object,		EBO

其中EBO又可以叫做 : IBO(Index Buffer Object) 索引缓冲对象 ,EBO是比较常见的叫法。

当我们使用OpenGL绘制图形时,需要将顶点的位置、颜色等信息传递给显卡,让显卡进行绘制。

1、VBO(Vertex Buffer Object)是用来存储这些顶点数据的特殊缓冲区,可以将数据保存在显卡中,避免频繁地从CPU传输数 据到显卡,提高绘制效率。

2、VAO(Vertex Array Object)则是用来管理这些顶点数据的设置的。
绘制一个图形通常需要多个顶点属性(比如位置、颜色等),VAO帮助我们预先指定这些属性在VBO中的排列方式,
避免在每次绘制时重新设置属性,简化绘制代码。

3、EBO(Element Buffer Object)是用来存储图元的索引数据的缓冲区,比如三角形的三个顶点索引。
它可以帮助我们避免重复存储顶点数据,只需存储少量的索引数据就可以描述复杂的图形,提高绘制效率。

综合来说,VBO、VAO和EBO是帮助我们优化OpenGL绘制图形的工具。

VBO将顶点数据存储在显卡中,
VAO管理这些数据的属性设置,
EBO帮助我们高效描述复杂图形的顶点索引。

它们的组合可以让我们更高效地绘制图形,让图形的渲染速度更快,性能更好。

在这里插入图片描述

简单来说EBO可以根据顶点数据中的下标,绘制对应样式的结构。

GLfloat vertices_1[] = 
{
    0.0f,   700.0f,   0.0f,
	0.0f,   0.0f,     0.0f,
	700.0f, 0.0f,     0.0f,
	700.0f, 700.0f,   0.0f,
	
};

GLfloat vertices_2[] = 
{
	0.0f, 0.0f, 0.0f,
	0.0f, 1.0f, 0.0f,
	0.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f,
};

GLint vertices_3[] = 
{
	0,1,3,
    1,2,3,
};

vertices_1是顶点数据,vertices_2是每个顶点的颜色定义,vertices_3即是EBO,用来控制最终绘制的结构。可以参考上图矩形理解。

main.cpp

#include <iostream>

#include "glew.h"
#include "glfw3.h"

#include "glm/glm.hpp"                  // GLM 的基本数学类型,例如 glm::mat4 和 glm::vec3
#include "glm/gtc/matrix_transform.hpp" // GLM 的矩阵变换函数,例如 glm::ortho
#include "glm/gtc/type_ptr.hpp"         // 用于 glm::value_ptr 函数


#include "log.h"
#include "GlslDealConfig.h"

GLfloat vertices_1[] = 
{
    0.0f,   700.0f,   0.0f,
	0.0f,   0.0f,     0.0f,
	700.0f, 0.0f,     0.0f,
	700.0f, 700.0f,   0.0f,
	
};

GLfloat vertices_2[] = 
{
	0.0f, 0.0f, 0.0f,
	0.0f, 1.0f, 0.0f,
	0.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f,
};

GLint vertices_3[] = 
{
	0,1,3,
    1,2,3,
};

int main()
{
    GlslDealConfig mdeal;
    int major = 0, minor = 0, rev = 0;
    glfwGetVersion(&major, &minor, &rev);
    LOGI("glfw version %d - %d - %d", major,minor,rev);

    if (glfwInit() == GLFW_FALSE)
    {
        LOGE("glfwInit failed");
        return 0;
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(700, 700, "Ebo", NULL, NULL);
    if (window == NULL)
    {
        LOGE("glfwCreateWindow failed");
        return 0;
    }

    glfwMakeContextCurrent(window);

    GLenum err = glewInit();
    if (err != GLEW_OK)
    {
        LOGE("glew init failed : %s", reinterpret_cast<const char*>(glewGetErrorString(err)));
        return 0;
    }

    glfwSwapInterval(1);

    std::string vertexShader = mdeal.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/VaoAndVbo/VertexShader.glsl");
    std::string fragmentShader = mdeal.ReadGlslFile("/home/ryan/zxp/Rendering/demo/glsl/VaoAndVbo/FragmentShader.glsl");

    const GLchar *vData = vertexShader.c_str();
    const GLchar *fData = fragmentShader.c_str();

    GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
    GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);

    glShaderSource(vShader,1,&vData,NULL);
    glShaderSource(fShader,1,&fData,NULL);

    glCompileShader(vShader);
    glCompileShader(fShader);

    GLuint Progma = glCreateProgram();
    glAttachShader(Progma,vShader);
    glAttachShader(Progma,fShader);
    glLinkProgram(Progma);

    glDeleteShader(vShader);
    glDeleteShader(fShader);

    GLuint VAO,VBO[2],EBO;

    glGenVertexArrays(1, &VAO);
    glGenBuffers(2, VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
    glBufferData(GL_ARRAY_BUFFER,sizeof(vertices_1),vertices_1, GL_STATIC_DRAW);
    glVertexAttribPointer(0,3, GL_FLOAT,GL_FALSE,3*sizeof(GLfloat),(void*)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
    glBufferData(GL_ARRAY_BUFFER,sizeof(vertices_2),vertices_2, GL_STATIC_DRAW);
    glVertexAttribPointer(1,3, GL_FLOAT,GL_FALSE,3*sizeof(GLfloat),(void*)0);
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(vertices_3),vertices_3, GL_STATIC_DRAW);

    glBindVertexArray(0);

    glm::mat4 projection = glm::ortho(0.0f, 600.0f, 0.0f, 600.0f, -1.0f, 1.0f);
    glUseProgram(Progma);
    GLuint projLoc = glGetUniformLocation(Progma, "projection");
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    // 绘制循环
    while (!glfwWindowShouldClose(window))
    {
        glViewport(0, 0, 700, 700);
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(Progma);
        glBindVertexArray(VAO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(2, VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteProgram(Progma);

    glfwTerminate();
    return 0;
}

注意

glDrawArrays

用途: 用于绘制一组连续的图形原语(例如,三角形、线段等)。
数据来源: 从当前绑定的顶点缓冲对象(VBO)中按顺序读取顶点数据。
不使用 EBO: glDrawArrays 不使用 EBO,因为它不需要索引来决定顶点的绘制顺序。

glDrawElements

用途: 用于绘制图形原语,但允许使用索引来指定哪些顶点需要被绘制。
数据来源: 顶点数据从绑定的 VBO 中读取,索引数据则来自于绑定的 EBO。
使用 EBO: glDrawElements 利用 EBO 中的索引来决定哪些顶点需要被绘制,从而可以重用顶点数据,避免冗余。

运行截图

在这里插入图片描述
感谢阅读^ _ ^
如有错误感谢指正。

### 回答1: OpenGLOpen Graphics Library)是一种跨平台的图形编程接口,可以用于开发2D和3D图形应用程序。下面是一些OpenGL项目实战教程: 1. 光照效果:学习如何使用OpenGL实现各种光照效果,例如平行光、点光源和聚光灯效果。通过调整光照参数和材质属性,可以创建逼真的光照场景。 2. 纹理映射:学习如何使用OpenGL将纹理映射到三维模型上。通过加载图像文件并将其应用于模型表面,可以实现逼真的贴图效果。 3. 阴影效果:学习如何使用OpenGL实现阴影效果,例如投影阴影和阴影贴图。阴影效果可以增强场景的逼真感和深度感。 4. 粒子系统:学习如何使用OpenGL创建粒子系统,例如火焰、烟雾和爆炸效果。通过调整粒子属性和行为,可以创建各种动态和生动的效果。 5. 物理模拟:学习如何使用OpenGL结合物理引擎实现物理模拟效果,例如碰撞检测、重力和运动模拟。通过模拟真实世界的物理规律,可以创建更真实的交互体验。 6. 游戏开发:学习如何使用OpenGL和其他游戏开发库(例如SDL或SFML)开发2D或3D游戏。从游戏引擎的搭建到游戏场景的渲染,可以实现自己的游戏创意。 这些项目实战教程可以帮助初学者学习并掌握OpenGL的基本概念和技术,同时也可以帮助有一定OpenGL经验的程序员进一步提升他们的图形编程能力。通过实际动手实现这些项目,可以更好地理解OpenGL的原理和使用方法,并能够应用于实际的图形应用程序开发。 ### 回答2: OpenGLOpen Graphics Library)是一个用于三维图形渲染的跨平台开放式图形库。它提供了一系列的函数和工具,帮助开发人员创建高性能的图形应用程序。 关于OpenGL项目实战教程,我可以给出以下几个方面的建议: 首先,了解基础知识。在开始实战项目之前,需要掌握OpenGL的基本概念和原理,包括顶点缓冲对象、顶点数组对象、着色器、纹理等。可以通过查阅OpenGL的官方文档或相关教程来学习。 其次,选择一个合适的实战项目。可以根据自己的兴趣和实际需求选择一个合适的项目,比如创建一个简单的3D游戏、设计一个图形界面等。选择一个适合自己水平和时间的项目,逐步提升自己的技能。 然后,学习项目所需的技术和工具。根据项目的需求,可能需要学习一些额外的技术和工具,比如图形数学、碰撞检测、模型导入等。可以通过在线教程、书籍或论坛来学习这些知识,并逐步应用到自己的项目。 接下来,编写代码并调试。根据项目需求,使用OpenGL提供的函数和工具编写代码,并对代码进行调试。可以通过输出调试信息、使用调试工具等方式来排查问题并解决。 最后,不断学习和优化。OpenGL是一个庞大而复杂的库,可能需要不断地学习和掌握新的技术和工具。在实战过程,可以将学到的经验和技巧总结下来,并进行项目的优化,提高性能和用户体验。 总结起来,OpenGL项目实战教程需要学习基础知识、选择合适的项目、学习相关技术和工具、编写代码和调试,并不断学习和优化。通过实际的实践和项目经验,可以提升自己的OpenGL编程能力。 ### 回答3: OpenGLOpen Graphics Library)是一个用于渲染二维和三维图形的跨平台图形库。它提供了一系列函数用于操作图形、纹理、着色器等,能够实现复杂的图形渲染和动画效果。下面将简要介绍OpenGL项目实战教程OpenGL项目实战教程是一种通过实际项目来学习和实践OpenGL技术的教学方法。它通常基于具体的应用场景,通过逐步完成一个完整的项目,来引导学习者了解和掌握OpenGL的相关知识和技能。 在开始OpenGL项目实战教程之前,学习者需要具备一定的编程基础,如C++或Java等编程语言的基础知识。同时,对于图形学的基本概念和算法也有一定的了解。 在实战教程,教学者通常会选择具有代表性的项目,例如创建一个简单的3D游戏场景或实现一个基本的图形编辑器等。通过这些项目,学习者可以逐步了解和掌握OpenGL的基本概念、渲染流程、坐标系统、纹理映射、着色器编程等核心内容。 教程通常会结合理论和实践,通过讲解相关概念和技术,例如图形渲染管线、顶点和片段着色器、缓冲区对象等,来引导学习者完成项目的不同阶段。学习者可以借助开源的OpenGL库或框架,例如OpenGL ES、GLEW、GLFW等,加快项目的开发进程。 通过完成OpenGL项目实战教程,学习者可以获得以下几方面的收益。首先,他们可以将理论知识应用于实际项目,更深入地理解和掌握相关技术。其次,他们可以通过项目实战来锻炼编程能力和解决问题的能力。最后,完成的项目还可以作为学习者的作品展示,增强他们的简历或作为个人项目的起点。 总之,OpenGL项目实战教程是一种有效的学习和实践OpenGL技术的教学方法,可以帮助学习者深入了解和掌握OpenGL的相关知识和技能,同时提升他们的编程和解决问题的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值