如何使用OpenGL有效地渲染多个不同项目

时间:2018-10-21 13:12:14

标签: opengl lwjgl

我正在使用OpenGL(确切地说是LWJGL3)制作一个简单的STG引擎。在此游戏中,一帧中可以有几种不同类型的项目(称为子弹),每种类型可以具有10-20个实例。我希望找到一种有效的渲染方式。

我已经阅读了一些有关现代OpenGL的书,并找到了一种称为“实例化渲染”的方法,但是它似乎只能用于相同的实例。我应该使用for循环直接为我的情况绘制所有项目吗?

另一个问题是关于内存。由于项目数量总是在变化,我是否应该为每个帧创建一个VBO?

3 个答案:

答案 0 :(得分:1)

这不是最容易回答的问题,但是我会尽力而为。

OpenGL的重要属性是 OpenGL上下文始终绑定到单个线程。因此,每个OpenGL方法都必须在该线程中调用。解决此问题的常用方法是使用队列。

示例:
我们正在使用模型-视图-控制器体系结构。
我们有3个线程;一种阅读输入,一种处理收到的消息,一种呈现场景。
这里OpenGL上下文绑定到渲染线程。
第一个线程收到一条消息“将模型添加到位置x”。第一个线程没有时间处理该消息,因为可能紧接着有另一条消息出现,我们不想延迟它。因此,我们只需要将此消息添加到第二个线程的队列中,即可将其提供给第二个线程处理。 第二个线程在需要OpenGL上下文之前读取消息并执行所需的任务。 Like从内存中读取Wavefront(.obj)文件,并根据接收到的数据创建数组。
然后,我们的第二个线程将该数据排队到OpenGL线程中进行处理。 OpenGL线程生成VBO和VAO并将数据存储在其中。

返回您的问题
OpenGL生成的对象会保留在上下文内存中,直到手动将其删除或上下文被破坏为止。因此它的工作方式类似于C,在这种情况下,您必须手动分配内存并在不再使用内存后将其释放。因此,您不应为每个帧创建新的对象,而应重用保持不变的数据。同样,当您有多个使用相同模型或纹理的对象时,只需加载该模型一次,并将所有特定于对象的差异应用于着色器

示例:
您有一个环境,其中有10个岩石共享相同的岩石模型。
您加载数据,将其存储在VBO中,然后将这些VBO附加到VAO中。现在,您有了一个定义岩石的VAO。
您将生成10个均具有位置,旋转和比例的岩石实体。渲染时,首先绑定着色器,然后绑定模型和纹理,然后遍历石头实体,并为每个石头实体绑定该实体的位置,旋转和比例(通常存储在transformationMatrix中)并进行渲染。

bind shader
load values to shader's uniform variables that don't change between entities.
bind model and texture (as those stay the same for each rock)
for(each rock in rocks){
   load values to shader's uniform variables that do change between each rock, like the transformation.
   render
}
unbind shader

注意:如果仅使用一个着色器,则无需取消绑定/绑定每一帧的着色器。 VAO和所有其他OpenGL对象也是如此。因此,绑定还将保留在每个渲染周期中。

希望这对您入门有帮助。我还建议一些教程,可能会对它有更多的了解。

答案 1 :(得分:0)

  

我已经阅读了一些有关现代OpenGL的书,并找到了一种称为   “实例化渲染”,但似乎只能与“实例化渲染”一起使用   我应该使用for循环直接为我绘制所有项目   情况?

     

另一个问题是内存。我应该为每个内存创建一个VBO吗   框架,因为物品的数量总是在变化?

这两者都取决于您计划拥有的子弹数量。如果您认为子弹少于一千,则几乎可以肯定地将每个子弹都推到VBO并上载,最终用户不会注意到。如果您计划一些淫秽的物品,请不要这样做。

我想您应该在每个帧中编写所有内容,因为这是目前最简单的 操作,如果您开始注意到性能问题,则需要研究实例化或其他方法。当您“以后”使用时,您应该对OpenGL更熟悉,并找出优化它的方法,这些方法不会让您感到费解(不是说现在就在您的头上,但是更多的经验只会使它变得更简单)稍后)。

不在屏幕上的剔除子弹也应该放在雷达上。

如果您打算在屏幕上放置大量的子弹,那么您应该这样说,我们可以讨论更高级的方法,但是我的猜测是,如果您对当今的硬件达到此极限,那么您将拥有雄心勃勃的雄心缩小相机并在屏幕上显示大量实体的游戏,或者您被放大并可能在屏幕上出现混乱。

答案 2 :(得分:0)

20个对象什么都不是。无论您如何绘制,您的程序都将很快完成。

当您有10000个对象时,您将需要一种有效的方法。

在此之前,请以最方便的方式绘制它们。这可能意味着每个对象都要进行单独的绘制调用。