在线程之间同步VBO的最佳方法

时间:2017-01-30 12:34:00

标签: c# multithreading opengl graphics

所以我有一个像Minecraft一样的块系统,这意味着它是一个渲染数据块。当玩家四处移动并进入另一个块时,正在卸载超出范围的块,同时加载新的块,这使得它非常苛刻,因为渲染数据必须先在另一个线程中计算才能显示。

假设数据已经从磁盘加载,它看起来像这样

Main / Render Thread Render数据生成线程

   |         Request Chunk            |
   | -------------------------------> |
   |                                  |
   |                                  | Generating render data (FloatBuffer)
   |                                  |
   |                                  .
   |                                  .
   |                                  .
   |        Get Ready Chunks          |
   | <------------------------------- |
   |                                  |
   | Upload Data                      |
   |                                  |
   | Render                           |
   |                                  |

“请求块”和“Get Ready Chunks”不同步,因此渲染线程确实独立工作。

这样做的问题是,一次上传大量的块会导致陷阱,但计算我上传多少时间无法可靠地完成。如果我每帧只上一个,我会错过很多速度,虽然它工作正常(这就是它现在实现的方式)。

由于我只使用一个GL上下文,我现在只能在主线程中创建VBO。

有没有办法解决这个问题更有效,比如在另一个线程中创建VBO并将它们传递给主线程?

2 个答案:

答案 0 :(得分:2)

老实说,你限制每帧上传次数的方法可能是要走的路;即使是我曾经做过的商业游戏也是为了避免流媒体故障。在其他线程中完成所有可能的工作,然后在渲染线程中只进行提交。

加快这一步的一个有用的事情可能是考虑减少实际上每个块上传的数据量的方法。例如,在我自己的体素渲染器中,块大小为64x64x64,这意味着我只需要每个组件8位用于位置(有几个位用于备用)。而且我可以通过从像素着色器中的导数计算它们来节省提交法线。等等。

答案 1 :(得分:-1)

不幸的是,OpenGL本质上是单线程的。因此,您只能从单个线程进行OpenGL调用。你可以在一个单独的线程中加载一个块(就像你应该使用阻塞I / O一样),但最终将它上传到显卡需要从主OpenGL线程中发生。

您可以做的一件事是使用glBufferSubData()。它允许您将多块几何体分段上传而不是一次性上传。我不认为你完全可以摆脱障碍,所以也许你可以尝试在加载块时每帧传输恒定数量的几何体,这样你至少可以将过程分散到多个帧。