OpenGL 创建窗口/三角形VAO、VBO、EBO

使用OpenGL创建三角形

程序运行效果

OpenGL 创建窗口/三角形VAO、VBO、EBO_第1张图片

VAO vertex array object 顶点数组对象
VBO vertex buffer object 顶点缓冲对象
EBO element(index) buffer object 索引缓冲对象

VBO and VAO

Data Flow from CPU to GPU

  • Vertex Buffer Object (VBO)
    VBOs are buffers of data (bytes) on the GPU
    CPU sends all data to the GPU using VBOs before it is rendered
  • Vertex Array Object (VAO)
    VAOs are the link between VBO and shader variables
    Describe how to pull the data out of VBOs and feed it into the shader variables

VBO

所以VBO的作用就是将PC内存中的顶点数据缓冲到显卡的显存中:
CPU -> bytes(PC Memory) -> Display Card Memory -> GPU
CPU为通用的中央处理器,其特点是通用性,缺点是浮点运算能力,计算机的内存好处是CPU操作方便,相比显卡的显存来说,同时期相对来说显存会比内存速度更快,所以VBO的好处就是将磁盘到内存后的顶点数据缓冲到显卡,让GPU图形处理器去操作显存中的数据,而GPU对比CPU的好处就是图形图像的处理能力,浮点运算能力更强。
所以我们在渲染之前,让CPU使用VBO将所有数据发送到GPU,这样为我们的OpenGL处理图形带来效率的提升。
OpenGL 创建窗口/三角形VAO、VBO、EBO_第2张图片

VAO

VAO则是VBO和着色器shader变量之间的链接,描述如何从VBO中提取数据并将其提供给着色器变量。
(VAO <-> VBO) <-> shader variables
OpenGL 创建窗口/三角形VAO、VBO、EBO_第3张图片

Vertex Attribute Pointer 顶点属性指针

我们要操作VAO实际上就是使用顶点属性指针,并激活顶点属性数组。
OpenGL 创建窗口/三角形VAO、VBO、EBO_第4张图片

  • 将当前VBO绑定到当前VAO
  • 将着色器变量与当前VBO数据链接
  • 将布局信息封装在当前VAO中,以便稍后检索
    OpenGL 创建窗口/三角形VAO、VBO、EBO_第5张图片
    将此布局信息封装在当前VAO中,以便稍后检索
// 定义定点数组
GLfloat vertices1[] = {
    // 坐标              // 颜色
     0.4f, -0.4f, 0.0f,  1.0f, 0.0f, 0.0f,  // 右下 红
    -0.4f, -0.4f, 0.0f,  0.0f, 1.0f, 0.0f,  // 左下 绿
     0.0f,  0.4f, 0.0f,  0.0f, 0.0f, 1.0f   // 顶部 蓝
};
GLfloat vertices2[] = {
    // 坐标             // 颜色
    0.5f,  0.5f, 0.0f,  1.0f, 1.0f, 0.0f, // 右上 黄
    0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 1.0f, // 右下 品
    0.0f, -0.5f, 0.0f,  0.0f, 1.0f, 1.0f, // 左下 青
    0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 0.0f  // 左上 黑
};
// 定义索引数据
GLuint indices[] = {
    0, 1, 3,    // 起始顶点:右上 -> 右下 -> 左上
    1, 2, 3     // 第二顶点:右下 -> 左下 -> 左上
};

GLuint VBO[2], VAO[2], EBO;             // 我们通过VBO或者VAO来管理显存中的顶点数据 / 索引缓冲对象    
glGenBuffers(2, VBO);                   // 通过glGenBuffers函数和一个ID,这里ID为 '1',来创建VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);  // 将VBO(顶点缓冲)绑定到 GL_ARRAY_BUFFER 目标上
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
// 将顶点数据缓冲到显存
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_STATIC_DRAW);
glGenVertexArrays(2, VAO);      		// 通过glGenVertexArrays函数和一个ID,这里ID为 '1',来创建VAO
glBindVertexArray(VAO[0]);      		// 要想使用VAO,要做的只是使用glBindVertexArray绑定VAO。
                                    	// 从绑定之后起,我们应该绑定和配置对应的VBO和属性指针,之后解绑
                                    	// VAO供之后使用。当我们打算绘制一个物体的时候,我们只要在绘制物
                                    	// 体前简单地把VAO绑定到希望使用的设定上就行了。
glBindVertexArray(VAO[1]);
// 指向顶点属性的指针(操作VAO与Shader)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
// 激活顶点属性数组
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

// 产生`EBO`、绑定`EBO`到`索引数组缓冲`、缓冲索引数据
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
Created with Raphaël 2.2.0 GLFW Initiazation Create Window GLAD Initiazation Create VAO,VBO,EBO Vertex load to VBO(BufferData) GLSL Program Main Loop(VAO to Render) GLFW Terminate

运行后的效果:
进程
OpenGL 创建窗口/三角形VAO、VBO、EBO_第6张图片

main.cpp 代码

shader_s.h(hpp) 代码

这个hpp文件主要的目的就是读取:vertex shader、fragment shader 与 geometry shader 链接到 shader program

vertex shader 与 fragment shader 的 shader program 代码

文件:3.3.shader.vs
OpenGL 创建窗口/三角形VAO、VBO、EBO_第7张图片
#version 330 core 是说明我们使用的opengl版本: “opengl 3.3 core profile”。
vec3 实际上就是3个float分量值(列表)作为列表的vector向量类型,x,y,z
vec4 即4个分量的向量类型。
in、out 的意思是方向,in 表示输入到当前GLSL program中的变量,out 表示通过处理后输出到opengl的变量。
上面的gl_Position是我们需要控制VBO中顶点数据的坐标,我们通过uniform统一类型将opengl中通过使用矩阵变换后传入到当前shader program中,与vec4(aPos, 1.0f)即当前VBO中的顶点坐标进行向量乘法,实现平移。
ourColor是我们将VAO顶点属性数组中顶点属性指针所指向到VBO中的顶点的颜色数据获取并传入其中,实现顶点的颜色设置。
layout (location = n)VBO中顶点数据、颜色数据或则贴图数据所在的缩影获取出来,例如上面(location = 0)是获取顶点数据,(location = 1)则是顶点颜色数据的索引。

Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。第二,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。

文件:3.3.shader.fs
OpenGL 创建窗口/三角形VAO、VBO、EBO_第8张图片
out 是我们要输出的颜色(FragColor 就是片段着色器所需要处理颜色的变量)。
in 表示我们opengl程序向片段着色器传递的变量。
变量名已经说的很清楚了,ourColor是我们向着色器传递的颜色数据的变量,FragColor则是输出到片段着色器的颜色数据变量。

这两个文件中的内容属于GLSL即:OpenGL Shader Language,实际上就是C代码。

渲染管线与OpenGL的着色器:
OpenGL 创建窗口/三角形VAO、VBO、EBO_第9张图片
上面的流程,其实就是渲染管线中数据的流水线过程(其中着色器部分有3个:VS,GS,FS)

OpenGL 创建窗口/三角形VAO、VBO、EBO_第10张图片
OpenGL 创建窗口/三角形VAO、VBO、EBO_第11张图片

调用这2个文件,实际上是使用了Shadershader_s.h文件,代码:

Shader ourShader("src/shader/3.3.shader.vs", "src/shader/3.3.shader.fs");

在主循环中,我们渲染的时候需要使用:

ourShader.use();

你可能感兴趣的:(OpenGL)