当前位置: 首页 > 知识库问答 >
问题:

如何在OpenGL中跨原语重用顶点

姬英武
2023-03-14

我在C中使用OpenGL(技术上是EGL,在Jetson Nano上)

假设我想画N个四边形。想象一下一个彩色矩形列表。框架中可能有几千个这样的矩形。

我想使用两个顶点缓冲区:

  1. 定义每个四边形的几何形状。
  2. 定义每个四元组共有属性的函数。

第一个顶点缓冲区应定义每个四边形的几何体。它应该只有4个顶点,它的数据将只是一个四边形的角。比如:

0, 0, // top left
1, 0, // top right
0, 1, // bottom left
1, 1, // bottom right

然后,第二个顶点缓冲区应该只有所有矩形的x、y、宽度和高度。

x1, y1, width1, height1, color1,
x2, y2, width2, height2, color2,
x3, y3, width3, height3, color3,
x4, y4, width4, height4, color4,
x5, y5, width5, height5, color5,
x6, y6, width6, height6, color6,
... etc.

问题是矩形缓冲区中的每一项都应该应用于顶点缓冲区中的4个顶点。

有没有一种方法可以设置它,使它不断重复使用相同的4个四边形顶点为每个矩形,并应用相同的矩形属性一次4个顶点?

我在想象我可以做些什么,所以我说第一个顶点缓冲区应该每个顶点使用一个元素,然后环绕,但是第二个顶点缓冲区每四个顶点使用一个元素,或者类似的东西。

我怎么设置这个?

现在我需要一个顶点缓冲区,它只需要将四边形顶点重复一遍又一遍,就像我有实例一样。

0, 0, // (1) top left
1, 0, // 
0, 1, // 
1, 1  // 
0, 0, // (2) top left
1, 0, // 
0, 1, // 
1, 1, // 
0, 0, // (3) top left
1, 0, // 
0, 1, // 
1, 1, // 
... etc

我的第二个缓冲区复制每个顶点的数据

x1, y1, width1, height1, color1,
x1, y1, width1, height1, color1,
x1, y1, width1, height1, color1,
x1, y1, width1, height1, color1,
x2, y2, width2, height2, color2,
x2, y2, width2, height2, color2,
x2, y2, width2, height2, color2,
x2, y2, width2, height2, color2,
x3, y3, width3, height3, color3,
x3, y3, width3, height3, color3,
x3, y3, width3, height3, color3,
x3, y3, width3, height3, color3,
x4, y4, width4, height4, color4,
x4, y4, width4, height4, color4,
x4, y4, width4, height4, color4,
x4, y4, width4, height4, color4,
x5, y5, width5, height5, color5,
x5, y5, width5, height5, color5,
x5, y5, width5, height5, color5,
x5, y5, width5, height5, color5,
x6, y6, width6, height6, color6,
x6, y6, width6, height6, color6,
x6, y6, width6, height6, color6,
x6, y6, width6, height6, color6,
... etc.

这似乎非常低效,我只想指定前4个顶点一次,并让它以某种方式继续重用它们,而不是重复这4个顶点N次,在我的第一个缓冲区中总共有4*N个顶点。我只想为总共N个顶点的每个四边形指定一次x、y、宽度、高度和颜色属性,而不是为总共4*N个顶点的每个顶点指定一次。

我该怎么做?

共有1个答案

廖招
2023-03-14

一般来说,渲染一系列四边形的最有效方法是。。。渲染一系列四边形。您不发送宽度/高度或其他每个实例的信息;计算CPU上4个顶点的实际位置,并使用适当的缓冲区对象流技术将它们写入GPU内存。具体地说,避免只改变几个四边形;如果您的数据不是静态的,那么最好将其全部重新上传(到不同的/无效的缓冲区),而不是只在原地修改几个字节。

您假设的替代方案仅在两种情况下性能更好:如果将数据写入GPU的带宽是您当前的瓶颈(无论是由于quads还是您正在进行的其他传输),或者如果读取数据进行渲染的带宽是当前的瓶颈。

您可以通过减小顶点数据的大小来缓解这个问题。因为我们谈论的是二维四边形,所以你可以很好地为每个顶点的XY位置使用短线。或16位浮点数。不管怎样,这意味着每个顶点(位置颜色)只占用8个字节,这意味着四边形只有32个字节的数据。显然,12个字节少于32个(如果您使用类似的压缩,12个是每个实例的成本),但它仍然比完整的浮动位置使用的48个字节减少了33%。

如果你已经完成了分析作业,并且已经确定每四个32字节太多了,顶点实例化仍然是一个坏主意。众所周知,在某些硬件上,极小的实例会扼杀VS性能。因此,应该避免。

在这种情况下,最好放弃所有顶点属性的使用(VAO应该禁用所有数组,而VS应该在中没有定义值)。相反,您应该直接从SSBO获取实例数据。

gl\u VertexID输入值告诉您渲染的顶点索引。如果正在渲染四边形,则当前实例将是gl\u VertexID/4。四元网格中的当前顶点是gl\u VertexID%4。所以你的VS看起来像这样:

struct instance
{
  vec2 position;
  vec2 size;
  uint color; //Packed as 4 bytes; unpack with unpackUnorm4x8
  uint padding; //Padding needed due to alignment/stride of 8 bytes.
};

layout(binding = 0, std430) buffer instance_data
{
  instance instances[];
};

vec2[4] vertex_table =
{
  vec2{0, 0},
  vec2{1, 0},
  vec2{0, 1},
  vec2{1, 1},
};

void main()
{
    instance curr_instance = instances[gl_VertexID / 4];
    vec2 vertex = vertex_table[gl_VertexID % 4];

    vertex = curr_instance.position + (curr_instance.size * vertex);
    gl_Position = vec4(vertex.xy, 0.0, 1.0);
}

这类事情的速度完全取决于GPU处理此类全局内存读取的能力。请注意,至少可以假设将每个实例数据的大小减少回12。您可以使用unpunorm2x16unpuhalf2x16分别解压这些值,将位置和大小打包为两个16位短或半浮。如果这样做,那么您的实例结构只有3个uint值,并且不需要填充。

 类似资料:
  • 我真的不明白片段着色器是如何工作的。 我知道 顶点着色器每个顶点运行一次 片段着色器对每个片段运行一次 由于片段着色器不是按顶点而是按片段工作,它如何将数据发送到片段着色器?顶点的数量和片段的数量不相等。 它如何决定哪个碎片属于哪个顶点?

  • 我需要优化我的渲染代码,目前我正在使用glPushMatrix()和glTranslatef()以及glRotatef()。但这比在单个顶点数组调用中渲染所有对象的成本更高。 OpenGL中是否有一些快速的内置函数可以像glRotatef()一样旋转我的顶点数据?如果没有,你会推荐使用什么库或方法?我所知道的唯一方法是使用sin/cos函数来旋转顶点,但我不确定这是否是最快的方法,或者它甚至会导致

  • 我正在尝试LWJGL库,但我有点困惑。当我尝试渲染具有2d顶点的四边形时:glVertex2f(0,0);glVertex2f(0, 1000);glVertex2f(1000, 1000);glVertex2f(1000, 0);,那么一切似乎都很好,但是当我使用下面的代码时,我只看到黑屏。是我使用了错误的坐标,因此它没有显示在屏幕上,还是其他问题?

  • 问题内容: 我想编写一个非常简单的Java 3D编辑器(用于实验)。我了解JavaFX的基本用法,并且了解足够的OpenGL知识。但是我所有的OpenGL经验都是来自使用C / C ++。 我可以在JavaFx应用程序中制作“画布”并在其上映射OpenGL视口吗? 问题答案: 在内部,JavaFX可以将OpenGL用作渲染管道,因此需要在两者之间进行一些集成以避免冲突。 JavaFX中的OpenG

  • 我正在工作的OpenGL 2D游戏与雪碧图形。最近有人建议我应该使用OpenGL ES调用,因为它是OpenGL的子集,可以让我更容易地将它移植到移动平台上。大部分代码只是调用draw_image函数,其定义如下: 我需要修改什么才能使这个OpenGL ES兼容?另外,我使用固定函数而不是着色器的原因是我在一台不支持GLSL的机器上开发。

  • 问题内容: 我尝试将本教程与Golang一起使用:http : //www.opengl- tutorial.org/beginners-tutorials/tutorial-2-the-first- triangle/ go-version打开窗口并使背景变蓝,但是不显示三角形。C版本确实显示了它。这是Go中的代码: 这是c中有效的代码: 也许我给了vertexAttrib.AttribPoin