【问题标题】:A way of generating chunks一种生成块的方法
【发布时间】:2014-01-03 07:52:26
【问题描述】:

我正在制作一款游戏,而我实际上正在生成地图。

地图是使用一些算法程序生成的。这没有问题。

问题是我的地图可能很大。所以我考虑过将地图分割成块。

我的块没问题,每个块都是 512*512 像素,但唯一的问题是:我必须生成纹理(实际上是 SFML 中的 RenderTexture)。生成大约需要 0.5 毫秒,因此每次生成块时游戏都会冻结。

我想了一个办法来解决这个问题:我用工厂制作了一种线程池。我只需向它发送一个任务,它就会创建块。

现在已经全部实现了,它会引发 opengl 警告,例如:

“RenderTarget.cpp (219) 中的内部 OpenGL 调用失败:GL_INVALID_OPERATION,当前状态下不允许指定的操作”。

我不知道这是否是处理块的好方法。我也考虑过将块保存到图像/文件中,但我担心保存/加载它们需要太多时间。

你知道处理这种“无限”地图的更好方法吗?

【问题讨论】:

  • OpenGL 调用只能从单个线程进行。虽然技术上可以在 OpenGL 中使用多线程,但它不会加速任何事情(除非您有 2 个或更多显卡)。
  • @Builer_K 实际上,如果您花费大量精力在 GPU 和 CPU 之间移动数据,则很有可能使用多个线程来仅在单个 GPU 上提高 OpenGL 性能。见seas.upenn.edu/~pcozzi/OpenGLInsights/…
  • 如果你想拥有无限数量的块,那么你需要不时保存/加载它们,最后你根本没有更多的内存来用于块。

标签: opengl map sfml procedural-generation


【解决方案1】:

这是一个无效的操作,因为您必须将上下文绑定到每个线程。更重要的是,所有 GL 窗口系统 API 都在线程和上下文之间强制执行严格的 1:1 映射……没有线程可以绑定多个上下文,也没有上下文可以绑定到多个线程。您需要做的是使用共享上下文(一个用于绘图的上下文,一个用于每个工作线程),缓冲区对象和纹理等内容将在所有 shared 上下文之间共享但状态机和容器对象(如 FBO 和 VAO)不会。

您是在为这张地图使用平铺渲染,还是这只是一个巨大的纹理?

如果您不需要更新“块”图像的各个子区域,您只需在工作线程中创建新纹理即可。工作线程可以创建新的纹理并在绘图线程执行其业务时为其提供数据。只有在工作线程完成后,您才会真正尝试使用其中一个块进行绘制。这可能会增加块开始加载和最终出现​​在完成的场景之间的整体延迟,但您应该获得更一致的帧速率。

如果您需要为此使用单个纹理,我建议您对纹理进行双重缓冲。有一个你在绘图线程中使用,另一个你的工作线程发出glTexSubImage2D (...)。当工作线程完成更新其纹理区域时,您可以交换用于绘制和更新的纹理。这将减少所需的同步量,但会再次增加更新最终出现在屏幕上之前的延迟。

【讨论】:

  • 哦,我还没有尝试在将 RenderTexture 发送到线程之前对其进行实例化,这可能是个好主意!
  • 如果你不实现上下文共享,那仍然行不通。 RenderTexture 中的术语 Render 表示您将积极使用 OpenGL 进行渲染。您要么必须在线程之间共享上下文,要么在执行这些操作之前将上下文与绘图线程解除绑定并将其提供给工作线程(这几乎是不切实际的)。我的观点实际上是,如果您使用共享渲染上下文,那么工作线程实际上可以创建用于主绘图线程的纹理。
  • 但老实说,0.5 毫秒并不是一个不合理的更新时间,如果你愿意,你可以使用完整的 16 毫秒达到 60 FPS。如果您的软件以必须串行而不是并行执行这些更新的方式编写或仅限于每帧几次更新,那确实变得不合理。
  • 嗯,这比 0.5 多 5ms,对不起。我想我会线程化图形引擎。
【解决方案2】:

要尝试的事情:

  • 让你的块更小
  • 在单独的线程中生成块,但从主线程传递到 gpu
  • 一次将一小块传递给 gpu,需要一两秒

【讨论】:

猜你喜欢
  • 2012-07-07
  • 1970-01-01
  • 2021-11-01
  • 2022-12-24
  • 2013-03-10
  • 2018-04-17
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
相关资源
最近更新 更多