现在,我正在建模某种小型的OpenGL库,以图形化编程等方式蒙混过关。因此,我使用类来包装特定的OpenGL函数调用,如纹理创建,着色器创建等等, 到现在为止还挺好。OpenGL对象创建
我的问题:
所有OpenGL调用必须由拥有创建OpenGL上下文的线程来完成(至少在Windows下,所有其他线程将什么也不做,创建一个OpenGL错误)。所以,为了获得OpenGL上下文,我首先创建一个窗口类的实例(只是Win API调用的另一个包装),最后为该窗口创建一个OpenGL上下文。这听起来对我来说很合逻辑。 (如果在我的设计中已经有一个让你尖叫的缺陷,请告诉我...)
如果我想创建一个纹理,或任何其他需要OpenGL调用创建的对象,我基本上这样做( OpenGL的对象调用的构造函数,例如):
opengl_object()
{
//do necessary stuff for object initialisation
//pass object to the OpenGL thread for final contruction
//wait until object is constructed by the OpenGL thread
}
所以,在的话,我创建一个对象,就像使用任何其他对象
opengl_object obj;
,然后在其构造器,把自己变成一个队列的OpenGL对象将由OpenGL上下文线程创建。然后,OpenGL上下文线程调用一个虚拟函数,该函数在所有OpenGL对象中实现,并包含必要的OpenGL调用以最终创建该对象。
我真的认为,这种处理这个问题的方式会很好。但是,现在,我认为我非常错误。
虽然上述方法迄今为止工作得非常好,但在类层次更深时,我会遇到麻烦。例如(这不是完美的,但它表明我的问题):
比方说,我有一个名为sprite的类,显然表示一个Sprite。它对OpenGL线程有自己的创建函数,其中顶点和纹理坐标被加载到图形卡存储器中等等。到目前为止,这没有问题。让我们进一步说,我想有2种渲染精灵的方式。一个实例,一个通过另一种方式。所以,我最终会得到2个类,sprite_instanced和sprite_not_instanced。两者都来自精灵类,因为它们都是精灵,它们的渲染方式不同。但是,sprite_instanced和sprite_not_instanced在其create函数中需要进一步的OpenGL调用。
我的解决方案至今(我觉得真的很可怕呢!)
我有某种C++中工作以及它如何影响虚拟功能的理解如何对象生成。所以我决定只使用类精灵的虚拟创建函数来将顶点数据等加载到图形内存中。然后,sprite_instanced的虚拟创建方法将进行准备以呈现该精灵实例。 所以,如果我想要写
sprite_instanced s;
首先,精灵调用构造函数和一些初始化后,将构建线程传递对象到OpenGL的线程。在这一点上,传递的对象只是一个普通的精灵,所以sprite :: create将被调用,OpenGL线程将创建一个普通的精灵。之后,构造线程将调用sprite_instanced的构造函数,再次进行一些初始化并将对象传递给OpenGL线程。但是,这次是sprite_instanced,因此将调用sprite_instanced :: create。因此,如果我对上述假设是正确的,那么至少在我的情况下,所有事情都应该发生,就像它应该发生的一样。我花了最后一小时阅读关于从构造函数调用虚函数以及v-table如何构建等等。我已经运行了一些测试来检查我的假设,但这可能是编译器特定的,所以我不会依赖它们100% 。另外,它感觉很糟糕,并且像一个可怕的黑客。
另一种解决方案
另一种可能性是在实施了OpenGL线程类工厂方法来采取照顾。所以我可以在这些对象的构造函数中完成所有的OpenGL调用。然而,在这种情况下,我需要很多功能(或者一种基于模板的方法),并且感觉像OpenGL线程需要做的事情可能会导致渲染时间的损失...
我的问题
可以按照我上面描述的方式处理它吗?还是应该把这些东西丢掉,然后做点别的?
这对于所谓的“小型OpenGL库”来说是一个巨大的复杂性。它甚至是不必要的多线程。您列出的数据组织不会特别有效。您希望“精灵”的概念比“纹理”和“网格”等概念更高级别。 _更高一级。 –
是的,它变得非常大......我想我只是在很多不同的方式好奇。但是,我没有看到我所概述的数据组织将不会特别有效。你是用什么方式表示的?性能?可维护性?还有其他什么?也许这只是我在这里简化的一部分,但我想清除它... – Shelling
我发现(VS编译器),如果构造函数调用虚函数,总是调用基实现。但是如果我从构造函数调用的虚函数中调用虚函数,这可以正常工作。 – Luca