Lui*_*scu 4 opengl glsl vbo opengl-3 opengl-4
我正在尝试了解 OpenGL 背后的理论,目前正在研究 VBO。
到目前为止我的理解是:当我们声明一系列顶点时,比如说形成一个三角形基元的 3 个顶点,我们基本上不会将它们存储在任何地方,它们只是在代码中声明。
但是,如果我们想将它们存储在某个地方,我们可以使用 VBO 来存储这些顶点的定义。并且,通过同一个 VBO,我们将所有顶点信息发送到顶点着色器(这是一堆代码)。现在,VBO 位于 GPU 中,因此当我们调用 VBO 时,我们基本上将所有信息存储在 GPU 内存中。然后,作为管道渲染过程一部分的顶点着色器“来到”GPU 内存,“查看”VBO 并检索所有信息。换句话说,VBO存储顶点数据(三角形顶点)并将其发送到Vertex Shader。
因此,VBO -> 发送信息到 -> 顶点着色器。
它是否正确?我要求确定这是否是正确的解释,因为我发现自己在屏幕上画三角形,有时画由许多三角形组成的字母,还有一堆代码和函数,我基本上是通过记忆学到的,但并不真正理解什么他们是这样。
分解它:
// here I declare the VBO
unsigned int VBO;
// we have 1 VBO, so we generate an ID for it, and that ID is: GL_ARRAY_BUFFER
glGenBuffers(1, &VBO)
// GL_ARRAY_BUFFER is the VBO's ID, which we are going to bind to the VBO itself
glBindBuffer(GL_ARRAY_BUFFER, VBO)
// bunch of info in here that basically says: I want to take the vertex data (the
// triangle that I declared as a float) and send it to the VBO's ID, which is
// GL_ARRAY_BUFFER, then I want to specify the size of the vertex
// data, the vertex data itself and the 'static draw' thingy
glBufferData(...).
Run Code Online (Sandbox Code Playgroud)
完成所有这些操作后,VBO 现在包含其中的所有顶点数据。所以我们告诉 VBO,现在将其发送到顶点着色器。
这就是管道的开始,只是开始。
它是否正确?(我还没读过VAO是做什么的,在读之前我想知道我在脑海中解构VBO的方式是否正确,否则我会很困惑)
der*_*ass 14
我认为你混淆了很多不同的事情并且有一些困惑,所以我尝试按照你提出的顺序解决其中的大多数问题:
当我们声明一系列顶点时,比如说形成一个三角形基元的 3 个顶点,我们基本上不会将它们存储在任何地方,它们只是在代码中声明。
不。如果您“无处”存储数据,那么您就没有它。此外,您还在这里混淆了变量的声明、定义和初始化。对于顶点数据(与所有其他形式的数据一样),有两种基本策略:
您将数据存储在某个地方,通常是在文件中。直接在源代码中指定它仅意味着它存储在某个二进制文件中,可能是可执行文件本身(或其使用的某些共享库)
您通过一些数学公式或更一般的算法生成数据
方法1和方法2当然可以混合使用,通常方法2需要一些参数(这些参数本身需要存储在某个地方,所以参数又是情况1)。
并且,通过同一个 VBO,我们将所有顶点信息发送到顶点着色器(这是一堆代码)。现在,VBO 位于 GPU 中,因此当我们调用 VBO 时,我们基本上将所有信息存储在 GPU 内存中。
OpenGL 实际上只是一个规范,它完全不知道 GPU 的存在和 VRAM 的存在。因此,OpenGL 使用缓冲区对象(BO)的概念作为一定大小的连续内存块,完全由 GL 实现管理。作为用户,您可以要求 GL 创建或销毁此类 BO,指定它们的大小,并完全控制内容 - 如果您愿意,您可以将 MP3 文件放入 BO(并不是说有一个很好的用例)这)。
另一方面,GL 实现控制该内存的实际分配位置,并且实际上具有专用视频内存的 GPU 的 GL 实现可以选择将 BO 直接存储在 VRAM 中。像这样的提示可以帮助 GL 实现决定在哪里最好地放置这样的缓冲区(但是该提示系统有些缺陷,现代 GL 中存在GL_STATIC_DRAW更好的替代方案,但我不会在这里讨论)。GL_STATIC_DRAW意味着您打算一次指定内容并使用多次作为绘图选项的源- 因此数据不会经常更改(当然不会在每帧的基础上或更频繁地更改),并且它可能是如果存在这样的东西,将其存储在 VRAM 中是个好主意。
然后,作为管道渲染过程一部分的顶点着色器“来到”GPU 内存,“查看”VBO 并检索所有信息。
我认为可以这样说,尽管有些 GPU 有一个专用的“顶点获取”硬件阶段,它实际上读取顶点数据,然后将其馈送到顶点着色器。但这并不是真正重要的一点 - 顶点着色器需要访问每个顶点的数据,这意味着 GPU 将在顶点着色器执行之前或期间的某个时刻读取该内存(VRAM 或系统内存或其他)。
换句话说,VBO存储的是顶点数据(三角形顶点)
是的。用作顶点着色器的每顶点输入(“顶点属性”)源的缓冲区对象称为顶点缓冲区对象(“VBO”),因此直接遵循该术语的定义。
并将其发送到顶点着色器。
我不会这么说。BO 只是一块内存,它不会主动执行任何操作。它只是一个被动元素:它正在被写入或被读取。就这样。
Run Code Online (Sandbox Code Playgroud)// here I declare the VBO unsigned int VBO;
不,您正在编程语言的上下文中声明(并定义)一个变量,该变量稍后用于保存缓冲区对象的名称。在 GL 中,对象名称只是正整数(因此 0 被保留给 GL 作为“没有这样的对象”或“默认对象”,具体取决于对象类型)。
Run Code Online (Sandbox Code Playgroud)// we have 1 VBO, so we generate an ID for it, and that ID is: GL_ARRAY_BUFFER glGenBuffers(1, &VBO)
不。只是为新的缓冲区对象glGenBuffers(n,ptr)生成名称n,因此它将生成n以前未使用的缓冲区名称(并将它们标记为已使用),并通过将它们写入 指向的数组来返回它们ptr。因此,在这种情况下,它只是创建一个新的缓冲区对象名称并将其存储在您的VBO变量中。
GL_ARRAY_BUFFER与此无关。
Run Code Online (Sandbox Code Playgroud)// GL_ARRAY_BUFFER is the VBO's ID, which we are going to bind to the VBO itself glBindBuffer(GL_ARRAY_BUFFER, VBO)
不,GL_ARRAY_BUFFER不是 VBO 的 ID,VBO变量的值是 VBO 的 ID(名称!)。
GL_ARRAY_BUFFER是绑定目标。OpenGL 缓冲区对象可用于不同的目的,使用它们作为顶点数据的源只是其中之一,并GL_ARRAY_BUFFER指的是该用例。
请注意,经典 OpenGL 使用绑定概念有两个目的:
将缓冲区对象绑定到某些缓冲区对象绑定目标意味着您可以将该对象用于目标定义的目的。但请注意,缓冲区对象不会更改,因为它绑定到目标。您甚至可以同时将缓冲区对象绑定到不同的目标。GL 缓冲区对象没有类型。将缓冲区称为“VBO”通常仅意味着您打算将其用作GL_ARRAY_BUFFER,但 GL 并不关心。它确实关心GL_ARRAY_BUFFER调用时绑定的缓冲区是什么glVertexAttribPointer()。
Run Code Online (Sandbox Code Playgroud)// bunch of info in here that basically says: I want to take the vertex data (the // triangle that I declared as a float) and send it to the VBO's ID, which is // GL_ARRAY_BUFFER, then I want to specify the size of the vertex // data, the vertex data itself and the 'static draw' thingy glBufferData(...).
好吧,glBufferData只是为 GL 缓冲区对象创建实际的数据存储(即真实内存),这意味着您指定缓冲区的大小(以及我之前提到的使用提示,您告诉 GL 您打算如何使用内存),并且它可以选择允许您通过将数据从应用程序内存复制到缓冲区对象来初始化缓冲区。它不关心实际数据和您使用的类型)。
由于您使用GL_ARRAY_BUFFER此处作为目标参数,因此此操作将影响当前绑定为 的 BO GL_ARRAY_BUFFER。
完成所有这些操作后,VBO 现在包含其中的所有顶点数据。
基本上,是的。
所以我们告诉 VBO,现在将其发送到顶点着色器。
不会。GL 使用顶点数组对象(VAO),它存储每个顶点着色器输入属性在何处查找数据(在哪个缓冲区对象中、在缓冲区对象内的哪个偏移处)以及如何解释该数据(通过指定数据类型) )。
稍后在绘制调用期间,GL 将从缓冲区对象内的相关位置获取数据,如您在 VAO 中指定的那样。如果此内存访问是由顶点着色器本身触发的,或者如果有一个专用的顶点获取阶段读取之前的数据并将其转发到顶点着色器 -或者如果根本有一个 GPU - 完全是特定于实现的,并且与你无关。
这就是管道的开始,仅仅是开始。
好吧,取决于你如何看待事物。在传统的基于光栅化器的渲染管线中,“顶点获取”或多或少是第一阶段,顶点缓冲区对象将仅保存从中获取顶点数据的内存(并且VAO告诉它要使用哪些缓冲区对象,以及哪些实际位置以及如何解释它们)。