在空间中移动多个对象(存储在 VBO 中)的最有效方法是什么?我应该使用 glTranslatef 还是着色器?

2023-11-25

我试图在 opengl 中最有效地掌握移动物体(一般而言)和线带(特别是)的窍门,因此我正在编写一个应用程序,其中多个线段从右到左以恒定速度行进。在每个时间点,最左边的点将被删除,整条线将向左移动,并且在线的最右侧将添加一个新点(这个新数据点是动态流式传输/接收/计算的,每 10 毫秒左右)。为了说明我的意思,请看这张图片:

example showing line strip

因为我想处理许多对象,所以我决定使用顶点缓冲区对象,以尽量减少gl*来电。我当前的代码看起来像这样:

A) 设置初始顶点:

# calculate my_func(x) in range [0, n]
# (could also be random data)
data = my_func(0, n)

# create & bind buffer
vbo_id = GLuint()
glGenBuffers(1, vbo_id);
glBindBuffer(GL_ARRAY_BUFFER, vbo_id)

# allocate memory & transfer data to GPU
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW)

B)更新顶点:

draw():

  # get new data and update offset
  data = my_func(n+dx, n+2*dx)

  # update offset 'n' which is the current absolute value of x.
  n = n + 2*dx

  # upload data 
  glBindBuffer(GL_ARRAY_BUFFER, vbo_id)
  glBufferSubData(GL_ARRAY_BUFFER, n, sizeof(data), data)

  # translate scene so it looks like line strip has moved to the left.
  glTranslatef(-local_shift, 0.0, 0.0)

  # draw all points from offset
  glVertexPointer(2, GL_FLOAT, 0, n)
  glDrawArrays(GL_LINE_STRIP, 0, points_per_vbo)

where my_func会做这样的事情:

my_func(start_x, end_x):

  # generate the correct x locations.
  x_values = range(start_x, end_x, STEP_SIZE)

  # generate the y values. We could be getting these values from a sensor.
  y_values = []
  for j in x_values:
      y_values.append(random())

  data = []
  for i, j in zip(x_values, y_values):
     data.extend([i, j])

  return data

这工作得很好,但是如果我有 20 个跨越整个屏幕的线带,那么速度会大大减慢。因此我的问题是:

1)我应该使用glMapBuffer绑定GPU上的缓冲区并直接填充数据(而不是使用glBufferSubData)?或者这对性能没有影响吗?

2)我应该使用着色器来移动对象(这里是线条)而不是调用glTranslatef?如果是这样,这样的着色器会是什么样子? (我怀疑着色器是错误的方法,因为我的线带不是周期函数,而是包含随机数据)。

3)如果调整窗口大小会发生什么?如何相应地保持纵横比和缩放顶点? glViewport() 仅有助于在 y 方向上缩放,而不能在 x 方向上缩放。如果窗口在 x 方向上重新缩放,那么在我当前的实现中,我将不得不重新计算整个线带的位置(调用my_func获取新的 x 坐标)并将其上传到 GPU。我想这可以做得更优雅吗?我该怎么做呢?

4)我注意到当我使用glTranslatef对于非整数值,如果线带由数千个点组成,则屏幕开始闪烁。这很可能是因为我用来计算线带的精细分辨率与屏幕的像素分辨率不匹配,因此有时某些点出现在其他点的前面,有时出现在其他点的后面(当您不渲染线带时,这特别烦人)正弦波但有一些“随机”数据)。如何防止这种情况发生(除了平移 1 像素的整数倍的明显解决方案之外)?如果窗口的大小从最初的 800x800 像素调整为 100x100 像素,并且我仍然想要可视化 20 秒的线条带,那么在 x 方向上移动必须以某种方式以亚像素精度实现无闪烁,对吧?

5)如你所见,我总是打电话glTranslatef(-local_shift, 0.0, 0.0)- 从来没有做相反的事情。因此,我不断将整个视图向右移动。这就是为什么我需要跟踪绝对 x 位置(以便将新数据放置在正确的位置)。这个问题最终会导致出现伪影,即线条与窗口边缘重叠。我想一定有更好的方法来做到这一点,对吗?就像保持 x 值固定并仅移动和更新 y 值一样?

EDIT我删除了正弦波示例并用更好的示例替换它。我的问题通常是关于如何最有效地在空间中移动线带(同时向它们添加新值)。因此,任何像“预先计算 t -> 无穷大的值”这样的建议在这里都没有帮助(我也可以只是绘制在我家前面测量的当前温度)。

EDIT2考虑这个玩具示例,其中每个时间步之后,第一个点被删除,并在末尾添加一个新点:

t = 0

   * 
  * *    *
 *   **** *

 1234567890

t = 1

  * 
 * *    * *
    **** *

 2345678901

t = 2

 *        * 
  *    * *
   **** *

 3456789012

我想我不能在这里使用着色器,可以吗?

EDIT 3: example with two line strips. example showing two line strips

EDIT 4:根据蒂姆的回答,我现在使用以下代码,效果很好,但将线路分成两部分(因为我有两个电话glDrawArrays),另请参阅以下两个屏幕截图。

complete line incomplete line

# calculate the difference 
diff_first = x[1] - x[0]


''' first part of the line '''

# push the matrix
glPushMatrix()

move_to = -(diff_first * c)
print 'going to %d ' % (move_to)
glTranslatef(move_to, 0, 0)

# format of glVertexPointer: nbr points per vertex, data type, stride, byte offset
# calculate the offset into the Vertex
offset_bytes = c * BYTES_PER_POINT
stride = 0
glVertexPointer(2, GL_FLOAT, stride, offset_bytes)  

# format of glDrawArrays:  mode, Specifies the starting index in the enabled arrays, nbr of points
nbr_points_to_render = (nbr_points - c)
starting_point_in_above_selected_Vertex = 0
glDrawArrays(GL_POINTS, starting_point_in_above_selected_Vertex, nbr_points_to_render)  

# pop the matrix
glPopMatrix()


''' second part of the line '''

# push the matrix
glPushMatrix()

move_to = (nbr_points - c) * diff_first
print 'moving to %d ' %(move_to)
glTranslatef(move_to, 0, 0)


# select the vertex
offset_bytes = 0
stride = 0
glVertexPointer(2, GL_FLOAT, stride, offset_bytes)

# draw the line
nbr_points_to_render = c
starting_point_in_above_selected_Vertex = 0
glDrawArrays(GL_POINTS, starting_point_in_above_selected_Vertex, nbr_points_to_render)  


# pop the matrix
glPopMatrix()

# update counter
c += 1
if c == nbr_points:
    c = 0

EDIT5显然,最终的解决方案必须在屏幕上渲染一行,并且不能有任何两行缺少连接。 Tim 的循环缓冲区解决方案提供了如何移动绘图的解决方案,但我最终得到了两条线,而不是一条。


以下是我对修改后的问题的想法:

1)我应该使用glMapBuffer绑定GPU上的缓冲区并填充 直接数据(而不是使用 glBufferSubData)?或者这会不会导致 性能差异明智吗?

我不知道两者之间有任何显着的性能,但我可能更喜欢 glBufferSubData。

在您的情况下,我可能建议创建一个具有 N 个浮点数的 VBO,然后像循环缓冲区一样使用它。在缓冲区“结束”所在的本地位置保留一个索引,然后每次更新都会用新值替换“结束”下的值,并递增指针。这样,您只需在每个周期更新一个浮点数。

完成此操作后,您可以使用 2x 转换和 2x glDrawArrays/Elements 绘制此缓冲区:

想象一下,您有一个包含 10 个元素的数组,缓冲区结束指针位于元素 4 处。您的数组将包含以下 10 个值,其中 x 是常量值,f(n-d) 是随机样本d周期前:

0: (0, f(n-4) )
1: (1, f(n-3) )
2: (2, f(n-2) )
3: (3, f(n-1) )  
4: (4, f(n)   )  <-- end of buffer 
5: (5, f(n-9) )  <-- start of buffer
6: (6, f(n-8) )
7: (7, f(n-7) )
8: (8, f(n-6) )
9: (9, f(n-5) )

绘制这个(伪猜测代码,可能不完全正确):

glTranslatef( -end, 0, 0);
glDrawArrays( LINE_STRIP, end+1, (10-end)); //draw elems 5-9 shifted left by 4
glPopMatrix();
glTranslatef( end+1, 0, 0);
glDrawArrays(LINE_STRIP, 0, end); // draw elems 0-4 shifted right by 5 

然后在下一个循环中,用新的随机值替换最旧的值,并将循环缓冲区指针向前移动。

2)我应该使用着色器来移动对象(这里是线条) 调用 glTranslatef?如果是这样,这样的着色器会是什么样子? (我 怀疑着色器是错误的方法,因为我的线带是 不是周期函数,而是包含随机数据)。

如果您使用我在 #1 中描述的方法,则可能是可选的。在这里使用它并没有什么特别的优势。

3)如果调整窗口大小会发生什么?我如何保持纵横比 相应的比例和比例顶点? glViewport() 仅有助于缩放 在 y 方向,而不是在 x 方向。如果窗口重新缩放 x 方向,那么在我当前的实现中我必须 重新计算整个线带的位置(调用my_func来 获取新的 x 坐标)并将其上传到 GPU。我猜这个 可以做得更优雅吗?我该怎么做呢?

您不必重新计算任何数据。只需在某个对您有意义的固定坐标系中定义所有数据,然后使用投影矩阵将此范围映射到窗口即可。如果没有更多细节,很难回答。

4)我注意到当我将 glTranslatef 与非整数值一起使用时, 如果线带由数千个组成,则屏幕开始闪烁 点。这很可能是因为我的分辨率很好 用于计算线带与像素分辨率不匹配 屏幕上有时会出现一些点 有时落后于其他点(当您 不渲染正弦波,而是渲染一些“随机”数据)。我怎样才能预防 这种情况不会发生(除了由一个人翻译的明显解决方案之外) 1 像素的整数倍)?如果一个窗口的大小被调整了 最初 800x800 像素到 100x100 像素,我仍然想要 想象一条 20 秒的线带,然后沿 x 方向移动 必须以亚像素精度工作,无闪烁,对吧?

你的假设似乎是正确的。我认为这里要做的事情要么启用某种抗锯齿功能(您可以阅读其他帖子了解如何做到这一点),要么使线条更宽。

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

在空间中移动多个对象(存储在 VBO 中)的最有效方法是什么?我应该使用 glTranslatef 还是着色器? 的相关文章

  • OpenGL缓冲区更新[重复]

    这个问题在这里已经有答案了 目前我正在编写一个模拟水的程序 以下是我所做的步骤 创建水面 平面 创建VAO 创建顶点缓冲区对象 在其中存储法线和顶点 将指针绑定到此 VBO 创建索引缓冲区对象 然后我使用 glDrawElements 渲染
  • OpenGL 3.1 中已弃用 glLineStipple

    glLineStipple在最新的 OpenGL API 中已被弃用 它被替换成什么 如果不更换 怎样才能达到类似的效果呢 我当然不想使用兼容性配置文件 抱歉 它还没有被任何东西取代 我想到的第一个模拟它的想法是几何着色器 您向几何着色器提
  • gldrawarrays 不绘制任何东西

    我正在尝试用 VBO 绘制一个三角形 我在窗口上没有看到任何像素 我也没有看到任何 GL ERROR 这是我尝试运行的代码 include
  • 如何使用边缘和内部镶嵌因子完成三角形面片镶嵌?

    I am just learning tessellation and i came across with below example for triangle patch tessellation but i am not sure h
  • OpenGL,如何独立旋转对象?

    到目前为止我的代码 void display void glClear GL COLOR BUFFER BIT GL DEPTH BUFFER BIT Clear Screen And Depth Buffer glLoadIdentity
  • 如何在 GLSL 1.3 和 OpenGL 2.1 中使用位运算

    我正在尝试编写一个使用许多位操作的着色器 事实上 从 glsl 1 30 开始就支持它们 但我只使用 OpenGL 2 1 有没有办法在我的 OpenGL 版本中使用位运算 所有 SM3 兼容 OpenGL 2 1 硬件支持limited整
  • OpenGL:顶点越多,性能越慢

    我正在开发一个程序的一部分 其中给定 xyz 坐标集合 制作 3D 模型 我已经完成了这张图片所需的所有功能 即平移 旋转 缩放 但是给出的 xyz 坐标越多 程序运行速度就越慢 我的程序在处理 29 000 个坐标时运行得非常流畅 但当我
  • 如何使用现代 OpenGL 在透视投影中绘制对象的正交轴? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我有带有透视投影的 3D 场景 我还可以选择场景中的一个对象 我需要为选定的对象绘制轴 问题是轴不会在透视投影中保存其大小 如果物体远离眼睛
  • OpenGL 使用着色器将 NV12 转换为 RGB24

    我尝试编写一个应用程序来在 OpenGL 中显示 YUV 图像 我使用此代码片段在 C 中成功将 Y UV 转换为 RGB source https blog csdn net subfate article details 4730514
  • GLSL 中统一浮点行为和常量浮点行为的不同

    我正在尝试在 GLSL 中实现模拟双精度 并且观察到一种奇怪的行为差异 导致 GLSL 中出现细微的浮点错误 考虑以下片段着色器 写入 4 浮点纹理以打印输出 layout location 0 out vec4 Output unifor
  • 移动/调整大小期间 opengl 窗口冻结

    我正在使用 LWJGL 开发游戏 移动窗口时 计划将来添加调整大小代码 渲染循环冻结 我希望它在移动时继续以某种方式运行 LWJGL 不包括 glutMainLoop Display属于OpenGL 而不是Java 相关代码 regular
  • glm 中矩阵值的顺序不正确?

    我开始使用GLM http glm g truc net通过 OpenGL 3 和 GLSL 进行数学运算的库 我需要正交投影来绘制 2D 图形 所以我编写了这个简单的代码 glm mat4 projection 1 0 projectio
  • glDeleteTextures在Windows上似乎没有释放纹理内存,有没有解决办法?

    我的 openGL 应用程序内存不足 遇到一些问题 我正在尝试找出我的问题 为此 我创建了一个小型测试程序 它基本上只是从调用 glDeleteTextures 的文件中加载一个巨大的纹理 然后再次加载它 如果我在 OSX 上运行这个测试程
  • OpenGL:始终相同的颜色

    我正在 Windows 上编写一个程序 使用c opengl 2 1 and SDL我在顶点颜色方面遇到了一些问题 我在用着glColor3f设置每个顶点集的颜色 但它似乎不起作用 无论我选择什么颜色 我都会将每个顶点绘制为红色 我检查了传
  • OpenGL什么时候完成函数中指针的处理?

    OpenGL有多项功能 http www opengl org wiki GLAPI glTexSubImage2D直接获取指针 他们中有一些从这些指针读取数据 http www opengl org wiki GLAPI glBuffer
  • 渲染缓冲区大于窗口大小 - OpenGL

    我正在尝试绘制大于屏幕尺寸 即 320x480 的渲染缓冲区 512x512 执行 glReadPixels 后 图像看起来是正确的 除非图像的尺寸超过了屏幕尺寸 在本例中 超过了水平 320 和垂直 480 是什么原因导致这种异常现象呢
  • 创建并使用我自己的纹理图集的 mipmap

    我目前正在使用自动 mipmap 生成 C OpenTK GL GenerateMipmap GenerateMipmapTarget Texture2D 我使用的纹理平铺为 16px 的块 所以我的问题是 是否可以使用不会缩小至 1x1
  • 具有交错缓冲区的 openGL glDrawElements

    到目前为止 我只使用了 glDrawArrays 并希望转向使用索引缓冲区和索引三角形 我正在绘制一个有点复杂的对象 其中包含纹理坐标 法线和顶点坐标 所有这些数据都收集到一个交错的顶点缓冲区中 并使用类似于以下的调用进行绘制 假设所有血清
  • 无法在 QGLWidget 中设置所需的 OpenGL 版本

    我正在尝试在 Qt 4 8 2 中使用 QGLWidget 我注意到 QGLWidget 创建的默认上下文不显示 OpenGL 3 1 以上的任何输出 Qt wiki 有一个教程 http qt project org wiki How t
  • 如何在片段着色器中将 gl_FragCoord 转换为世界空间点?

    我的理解是 如果您有视图投影矩阵 屏幕宽度和屏幕高度的逆矩阵 则可以将 gl FragCoord 转换为片段着色器中世界坐标中的点 首先 你转换gl FragCoord x and gl FragCoord y通过分别除以宽度和高度 然后将

随机推荐