OpenGL 中的 VBO 到底是什么?

2024-06-25

我正在尝试了解 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(...).

完成所有这些操作后,VBO 现在包含其中的所有顶点数据。所以我们告诉 VBO,现在将其发送到顶点着色器。

这就是管道的开始,仅仅是开始。

它是否正确? (我还没读过VAO是做什么的,在读之前我想知道我在脑海中解构VBO的方式是否正确,否则我会很困惑)


我认为你混淆了很多不同的事情并且有一些困惑,所以我尝试按照你提出的顺序解决其中的大多数问题:

当我们声明一系列顶点时,比如说形成一个三角形基元的 3 个顶点,我们基本上不会将它们存储在任何地方,它们只是在代码中声明。

不。如果您“无处”存储数据,那么您就没有它。你也混淆了宣言, 定义 and 初始化这里的变量。对于顶点数据(与所有其他形式的数据一样),有两种基本策略:

  1. 您将数据存储在某个地方,通常是在文件中。直接在源代码中指定它仅意味着它存储在某个二进制文件中,可能是可执行文件本身(或其使用的某些共享库)

  2. You 程序上通过一些数学公式或更一般地通过一些数学公式生成数据算法

方法1和方法2当然可以混合使用,通常方法2需要一些参数(它本身需要存储在某个地方,所以参数又是情况 1)。

并且,通过相同的 VBO,我们将所有顶点信息发送到顶点着色器(这是一堆代码)。现在,VBO 位于 GPU 中,因此当我们调用 VBO 时,我们基本上将所有信息存储在 GPU 内存中。

OpenGL 实际上只是一个规范,它完全不知道 GPU 的存在和 VRAM 的存在。因此,OpenGL 使用concept of 缓冲对象(BO)作为一定大小的连续内存块完全由 GL 实施管理。作为用户,您可以要求 GL 创建或销毁此类 BO,指定它们的大小,并完全控制内容 - 如果您愿意,您可以将 MP3 文件放入 BO(并不是说有一个很好的用例)这)。

另一方面,GL 实现控制该内存的实际分配位置,以及 GPU 的 GL 实现 实际上具有专用视频内存的设备可以选择将 BO 直接存储在 VRAM 中。这hints like GL_STATIC_DRAW在那里帮助 GL 实现决定在哪里最好地放置这样的缓冲区(但是提示系统有些缺陷,并且现代 GL 中存在更好的替代方案,但我不会在这里讨论)。GL_STATIC_DRAW表示您打算指定内容一次并使用可能的次数作为source绘图选项的 - 因此数据不会经常更改(当然不会以每帧为基础或更频繁地更改),如果存在这种情况,将其存储在 VRAM 中可能是一个非常好的主意。

然后,作为管道渲染过程一部分的顶点着色器“来到”GPU 内存,“查看”VBO 并检索所有信息。

我认为可以这样说,尽管有些 GPU 有一个专用的“顶点获取”硬件阶段,它实际上读取顶点数据,然后将其馈送到顶点着色器。但这并不是真正重要的一点 - 顶点着色器需要访问每个顶点的数据,这意味着 GPU 将在顶点着色器执行之前或期间的某个时刻读取该内存(VRAM 或系统内存或其他)。

换句话说,VBO存储的是顶点数据(三角形顶点)

是的。用作顶点着色器的每顶点输入(“顶点属性”)源的缓冲区对象称为顶点缓冲对象(“VBO”),因此直接遵循该术语的定义。

并将其发送到顶点着色器。

我不会这么说。 BO只是一块内存,它并不主动do任何事物。它只是一个被动元素:它正在被写入或被读取。就这样。

// here I declare the VBO 
unsigned int VBO;

不,您正在编程语言的上下文中声明(并定义)一个变量,并且该变量稍后用于保存name缓冲区对象的。在 GL 中,对象names只是正整数(因此 0 被保留给 GL 作为“没有这样的对象”或“默认对象”,具体取决于对象类型)。

// we have 1 VBO, so we generate an ID for it, and that ID is: GL_ARRAY_BUFFER 
glGenBuffers(1, &VBO) 

No. glGenBuffers(n,ptr)只是生成names for n新的缓冲区对象,所以它会生成n以前未使用的缓冲区名称(并将它们标记为已使用),并通过将它们写入指向的数组来返回它们ptr。因此,在这种情况下,它只是创建一个新的缓冲区对象名称并将其存储在您的VBO多变的。

GL_ARRAY_BUFFER与此无关。

// GL_ARRAY_BUFFER is the VBO's ID, which we are going to bind to the VBO itself 
glBindBuffer(GL_ARRAY_BUFFER, VBO)

No, GL_ARRAY_BUFFER不是VBO的ID,而是你的值VBO变量是 VBO 的 ID(名称!)。GL_ARRAY_BUFFER is the 结合目标。 OpenGL 缓冲区对象可用于不同的目的,将它们用作顶点数据的源只是其中之一,并且GL_ARRAY_BUFFER指的是该用例。

请注意,经典 OpenGL 使用的概念binding有两个目的:

  1. 绑定使用:每当您发出依赖于某些 GL 对象的 GL 调用时,您想要使用的对象当前必须绑定到某些(特定的,取决于用例)绑定目标(不仅是缓冲区对象,还包括纹理和其他对象) )。
  2. 绑定到修改:每当您作为用户想要修改某个对象的状态时,您必须先将其绑定到某个绑定目标,并且所有对象状态修改函数都不直接将要处理的GL对象的名称作为参数,但绑定目标,并且会影响当前绑定在该目标的对象。 (现代GL也有直接状态访问它允许您修改对象而不必先绑定它们,但我也不会在这里详细介绍这一点)。

将缓冲区对象绑定到某些缓冲区对象绑定目标意味着您可以将该对象用于目标定义的目的。但请注意,缓冲区对象不会更改,因为它绑定到目标。您可以将缓冲区对象绑定到不同的目标即使在同一时间。 GL 缓冲区对象没有类型。将缓冲区称为“VBO”通常仅意味着您打算将其用作GL_ARRAY_BUFFER,但GL不在乎。它确实关心缓冲区的绑定是什么GL_ARRAY_BUFFER在当时的glVertexAttribPointer() call.

// 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(...).

Well, glBufferData只是创建实际的数据存储对于GL缓冲区对象(即真实内存),这意味着您指定缓冲区的大小(以及我之前提到的使用提示,您告诉GL您打算如何使用内存),并且它可选地允许您初始化通过将数据从应用程序内存复制到缓冲区对象来访问缓冲区。它不关心实际数据和您使用的类型)。

自从你使用GL_ARRAY_BUFFER这里作为目标参数,该操作会影响当前绑定的BOGL_ARRAY_BUFFER.

完成所有这些操作后,VBO 现在包含其中的所有顶点数据。

基本上,是的。

所以我们告诉 VBO,现在将其发送到顶点着色器。

否。GL 使用顶点数组对象(VAO),它存储每个顶点着色器输入属性在哪里查找数据(在哪个缓冲区对象中,在缓冲区对象内的哪个偏移处)以及如何解释该数据(通过指定数据类型)。

稍后在绘制调用期间,GL 将从缓冲区对象内的相关位置获取数据,如您在 VAO 中指定的那样。如果此内存访问是由顶点着色器本身触发的,或者如果有一个专用的顶点获取阶段读取之前的数据并将其转发到顶点着色器 -或者如果有 GPU- 完全是特定于实现的,与您无关。

这就是管道的开始,仅仅是开始。

好吧,取决于你如何看待事物。在传统的基于光栅化器的渲染管线中,“顶点获取”或多或少是第一阶段,顶点缓冲区对象将仅保存从中获取顶点数据的内存(以及告诉它要使用哪些缓冲区对象,以及哪些实际位置以及如何解释它们)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenGL 中的 VBO 到底是什么? 的相关文章

  • 在着色器中旋转法线

    我有一个场景 其中有多个具有各自位置和旋转的模型 给定法线 着色器对每个像素应用简单的双向照明 那是我的顶点着色器 version 150 in vec3 position in vec3 normal in vec2 texcoord o
  • 如何在片段着色器中将 gl_FragCoord 转换为世界空间点?

    我的理解是 如果您有视图投影矩阵 屏幕宽度和屏幕高度的逆矩阵 则可以将 gl FragCoord 转换为片段着色器中世界坐标中的点 首先 你转换gl FragCoord x and gl FragCoord y通过分别除以宽度和高度 然后将
  • 使用普通画布/文本输出更新LayeredWindow

    有没有一种方法可以使用画布在表单上绘图 然后使用 updatelayeredwindow 这样表单就不可见 但文本可见 就像只显示文本的半透明表单一样 如果没有 那么有没有办法只用画布 opengl directx 制作某种半透明形式 我想
  • Retina 显示屏中具有 QOpenGLWIdget 的 Qt MainWindow 显示错误大小

    我有一个 Qt 应用程序MainWindow 我嵌入一个QOpenGLWidget在里面 一切正常 直到我开始使用 Apple Retina 显示屏并在高 DPI 模式下运行我的应用程序 我的QOpenGLWidget只是它应该具有的大小的
  • 进行亚像素平移时,2D 纹理会扭曲

    我想知道一个理论推理为什么这是可能的 几何体的平移与纹理映射有何关系 我只能在进行子像素平移时注意到这种效果 如果通过整个像素平移 纹理看起来很好 我正在使用正交投影 GL CLAMP TO EDGE GL NEAREST 片段着色器是hi
  • OpenGL 缓冲区、glFlush 和 glutSwapBuffers()

    使用之间有什么区别吗 glutInitDisplayMode GLUT SINGLE GLUT RGB with glFlush and glutInitDisplayMode GLUT DOUBLE GLUT RGB with glutS
  • 如何使用OpenGL数组纹理?

    我正在尝试在OpenGL中使用精灵表 通过数组纹理实现它这就是我加载纹理的方式 QImage image image load C QtProjects project images spritesheet png png const un
  • 如何在 R 中导入并绘制三角形网格?

    我想在 R 中绘制我的模型输出 它是格式为的三角形网格 x1 y1 z1 x2 y2 z2 x3 y3 z3 value 每行代表一个三角形 我想用以下方法绘制这些三角形value作为规模 mymesh lt structure c 0 9
  • 3D 图形批处理

    很多网站 文章都说 批量 批 批 有人可以解释一下着色器中的 批处理 代表什么吗 即 是否 改变纹理 更改任意着色器变量 意味着某些东西不能 批处理 最简单的总结方法就是尝试尽可能少地调用 API 来绘制您需要绘制的内容 使用顶点数组或 V
  • sRGB 纹理。它是否正确?

    我最近阅读了一些有关 sRGB 格式以及它们如何允许硬件自动对典型显示器执行色彩校正的文章 作为我阅读的一部分 我发现您可以使用普通纹理和返回结果上的 pow 函数来模拟此步骤 无论如何 我想问两个问题 因为我以前从未使用过此功能 首先 有
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前
  • 并排显示图像的一半 - OpenGL

    我为两个图像创建了两个纹理 现在我想在opengl中按图像2的左侧部分 完整的图像1 图像2的右侧部分的顺序显示该纹理 我已经做了如下 Image1 显示在 opengl 屏幕的中央 但屏幕的左右部分不正确 应分别显示 image2 的左侧
  • OpenGL各向异性过滤支持,检查结果矛盾

    当检查是否支持各向异性过滤时 我得到矛盾的结果 if glewIsSupported GL EXT texture filter anisotropic GLEW EXT texture filter anisotropic std cou
  • OpenGL 中的 VBO 到底是什么?

    我正在尝试了解 OpenGL 背后的理论 目前正在研究 VBO 到目前为止我的理解是 当我们声明一系列顶点时 比如说形成一个三角形基元的 3 个顶点 我们基本上不会将它们存储在任何地方 它们只是在代码中声明 但是 如果我们想将它们存储在某个
  • 如何获取片段的当前颜色?

    我正在尝试了解 GLSL 中的着色器 并且找到了一些有用的资源和教程 但我一直在寻找一些应该是基本且微不足道的东西 我的片段着色器如何检索当前片段 你通过说设置最终颜色gl FragColor whatever 但显然这是一个仅输出值 如何
  • 如何创建多停止渐变片段着色器?

    我正在尝试创建一个 OpenGL ES 2 0 片段着色器 它沿一个轴输出多个停止渐变 它应该在以百分比定义的点处的多种颜色之间进行插值 我已经通过使用实现了这一点if是片段着色器 如下所示 float y gl FragCoord y f
  • GCC、字符串化和内联 GLSL?

    我想使用宏字符串化来声明内联 GLSL 着色器字符串 define STRINGIFY A A const GLchar vert STRINGIFY version 120 n attribute vec2 position void m
  • 围绕 glutMainLoop 执行程序的其余部分?

    我目前正在开发一个项目 其中有一个 android 应用程序 我在 PC 上的 OpenGL 窗口中编写了控件和对象 我已经让 OpenGL 窗口执行我想要的操作 并且我从 Android 设备获取了数据以流式传输到终端 但是我需要将数据传
  • OpenGL 和多个 GPU - 一般可能性

    我想知道 是否可以在多个 GPU 上同时运行多窗口 OpenGL 应用程序 更具体地说 假设我创建了一个应用程序 其中有两个窗口 每个窗口彼此共享 GL 上下文 现在 如果我将其中一个窗口从显示器 1 在 GPU 1 上运行 移动到显示器

随机推荐

  • 在 VSCode 中运行任何 Python 脚本时出现与“&”语法错误?

    在 VSCode 中 我通常使用 Python 扩展运行 Python 脚本 然后右键单击 py 脚本并选择 在终端中运行 Python 文件 在今天之前 此方法运行良好 但现在我遇到了以下问题 C Users Python Python3
  • 映射警告时反应唯一键

    我对反应还很陌生 我面临着一个无法解决的问题 这是我的反应组件 import React from react import Header from Header import ContestPreview from ContestPrev
  • IE中是否有AJAX进度事件以及如何使用它?

    我尝试了所有我能想到的方法 至少可以实现 IE9 中的进度功能 但没有任何效果 所有其他浏览器都可以进入进度函数并编写测试文本 没有任何问题 希望有人能帮助我 谢谢你 var info document getElementById inf
  • .net 中的线程

    我有一个 winforms 应用程序的简单示例 我在目录选择器中选择一个目录 然后单击按钮循环遍历该目录并将目录中的每个文件复制到另一个目录中 我想在后台线程上进行文件复制以避免锁定 GUI 我正在寻找最简单的解决方案 创建后台线程 传递源
  • 语言之间的 Unicode 范围映射

    此链接列出了 7707 种语言http www sil org iso639 3 download asp http www sil org iso639 3 download asp and http en wikipedia org w
  • .NET 自然语言处理工具包 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 您能给我一些用于 NET 中自然语言处理的工具包和库吗 有类似 UIMA for NET 的工具吗 有SharpNLP http shar
  • Oracle数据库中的自增主键

    我想在 SQL Server 的列中实现标识或自动递增值 CREATE TABLE RollingStock Id NUMBER IDENTITY 1 1 Name Varchar2 80 NOT NULL 如何才能做到这一点 正如 Orb
  • 为什么阴谋集团重新安装“总是危险的”?

    使用 Cabal 重新安装软件包时 通常会看到以下警告 警告 请注意 重新安装总是很危险的 无论如何继续 此消息背后的一些原因是什么 目前 重新安装软件包意味着破坏性地覆盖已安装的软件包 如果旧包对系统有任何反向依赖性 它们将不再工作 为了
  • VS 2013 和 MSBuild

    我最近升级到 Visual Studio 2013 这在使用 MSBuild API 或带有命令行参数的可执行文件 进行外部构建时导致了连续问题 Issue 1使用 MSBuild 构建时 它不会生成单元测试所需的假程序集 这会导致构建失败
  • 构建 Flask docker 镜像时分配端口

    我最近使用 Flask 创建了一个应用程序 并将 py 文件放入 docker 容器中 然而 我对人们分配端口的在线案例感到困惑 首先在我写的 py 文件的底部 if name main app run host 0 0 0 0 port
  • 使用表单传递数组和用户输入

    我在处理传递数组的表单时遇到困难 我在名为 product 的数组中包含了 5 个变量 a b c d e 然后将其传递到另一个框架使用表单以及需要用户输入值的输入 所以会同时传递一个数组和一个输入 那么我应该使用 post 还是 get
  • MonoTouch 错误:升级到 iOS 5.1 后“未安装 Apple iPhone SDK”

    我已将 iOS 5 0 1 升级到 5 1 并且使用 MonoTouch 5 2 5 和 MonoDevelop 2 8 6 5 当我在 MonoDevelop 中创建示例应用程序时 它显示错误 Apple iphone sdk 未安装 如
  • 如何显示带有排序下拉列表的页面?

    我有一个选择列表
  • 为什么在相同大小的类型之间进行强制转换时,reinterpret_cast 不强制使用 copy_n?

    根据cppreference com http en cppreference com w cpp language reinterpret cast reinterpret cast 通过重新解释底层位模式在类型之间进行转换 但是等等 这
  • 从用户访问令牌获取应用程序 ID(或验证令牌的源应用程序)

    我找到了这个question http facebook stackoverflow com questions 6816568 extract app id and user id from facebook access token 其
  • 快速计算幂(例如 2^11)[重复]

    这个问题在这里已经有答案了 可能的重复 实现基于整数的幂函数 pow int int 的最有效方法 https stackoverflow com questions 101439 the most efficient way to imp
  • Flask 上下文处理器函数

    按照 Flask 页面上的最小示例 我尝试构建一个上下文处理器 上下文处理器 py def inflect this def inflectorize number word return format number inflectoriz
  • 在android上使用正则表达式验证字符串

    我希望我的字符串不包含 and 我用这个代码 private static boolean IsMatch String s String pattern try Pattern patt Pattern compile pattern M
  • 如何在 vite svelte 中加载 env 进行生产

    所以我是 Vite 的新手 我将它用于我的 svelte 应用程序 我真的不明白这部分文档 在生产过程中 这些环境变量会被静态替换 因此 有必要始终使用完整的静态字符串来引用它们 例如 像 import meta env key 这样的动态
  • OpenGL 中的 VBO 到底是什么?

    我正在尝试了解 OpenGL 背后的理论 目前正在研究 VBO 到目前为止我的理解是 当我们声明一系列顶点时 比如说形成一个三角形基元的 3 个顶点 我们基本上不会将它们存储在任何地方 它们只是在代码中声明 但是 如果我们想将它们存储在某个