暴米花 发表于 2006-12-7 10:30:00

游戏引擎中的多渲染器的设计与实现(1)

<strong><br/><br/></strong>游戏引擎中的多渲染器的设计与实现(1) <p></p><p>  很多游戏引擎都提供了多种渲染器(DirectX,OpenGL,Software),甚至是多种平台(Windows,Linux,Mac),这对于引擎的设计和实现来说是一个很大的挑战,尤其是多渲染器,又要考虑到效率,又要考虑到通用,又要发挥每种渲染器的特点,这的确是一道天堑。这里讨论的原则很简单:&nbsp;1.&nbsp;Keep&nbsp;it&nbsp;simple;&nbsp;2.&nbsp;Make&nbsp;it&nbsp;work&nbsp;first.</p><p>  先看一下Ogre使用的方法。Ogre中各个模块是使用的插件式的设计“组合”在一起的,你可以在Ogre的基础上加入你自己写的渲染器,而不需要开动其他的代码(甚至是OgreMain引擎的主体部分的代码)。有很多的软件的架构都采用的类似的插件,最有名的像IDE&nbsp;Eclipse,&nbsp;引擎有如Unreal&nbsp;2,&nbsp;Unreal&nbsp;3等。写一个渲染器的插件并不很难,但是设计非插件的引擎内核是十分困难的。如果引擎的内核在初期没有设计好,在后期没有办法进行过多的修改;当然,如果设计得很好,那么对引擎进行功能的扩充或修改将是非常方便的(Unreal&nbsp;2&nbsp;就是使用了插件式的设计,在开发到中期后改掉了原来自己开发的物理模块,而是使用了Novodex)。</p><p>  另外一种方法是将渲染器的种类作为引擎的主模块构造函数(或者相关的初始化功能的函数)的参数。比如Irrilicht中就是用的这种方法,Irrilicht中,有一个CVideoNull纯虚类,不同的渲染器都继承于这个类;引擎的主模块有一个类CIrrDeviceWin32,其构造函数为:</p><p><br/><table cellspacing="1" cellpadding="4" width="80%" align="center"><tbody><tr><td class="code"><pre><br/>CIrrDeviceWin32(video::E_DRIVER_TYPE&nbsp;deviceType,&nbsp;<br/>                const&nbsp;core::dimension2d&lt;s32&gt;&amp;&nbsp;windowSize,&nbsp;u32&nbsp;bits,<br/>                bool&nbsp;fullscreen,&nbsp;bool&nbsp;stencilbuffer,&nbsp;bool&nbsp;vsync,&nbsp;IEventReceiver*&nbsp;receiver,<br/>                const&nbsp;wchar_t*&nbsp;version);<br/></pre></td></tr></tbody></table><br/></p><p>  其中E_DRIVER_TYPE为枚举类型,用来表示渲染器的类型。然后在构造函数的实现中,用switch来进行初始化基类渲染器。这种方法的缺点是,引擎框架在物理上,逻辑上存在循环依赖(这里指的是代码层面,也即编译层面上的依赖关系),主引擎部分依赖于各个渲染器,而各个渲染器又依赖于主引擎的其他部分。在编译时,这种设计的代价是巨大的。</p><p>  使用动态链接库是解决这个问题的方法之一,同时这也是插件式设计的实现手段(在linux中,有相应的机制shared&nbsp;object,由于我之前没有接触过linux上的编程,所以这里的讨论仅限于windows平台)。将原来的主引擎的构造函数中的代码改一下,依然还是用switch进行不同的渲染器的选择,只不过是调用不同的.dll来进行基类函数的构造。比如在ogre中,每一个渲染器都有一个导出到.dll的模块定义文件(.def文件),比如directx的渲染器中的.def文件的定义如下:</p><p><br/><table cellspacing="1" cellpadding="4" width="80%" align="center"><tbody><tr><td class="code"><pre><br/>LIBRARY&nbsp;RenderSystem_Direct3D9<br/>EXPORTS        <br/>                                dllStartPlugin&nbsp;@1<br/>                        dllStopPlugin&nbsp;&nbsp;@2<br/></pre></td></tr></tbody></table><br/></p><p><br/>其中dllStartPlugin和dllStopPlugin&nbsp;分别是创建和析构渲染器的函数,具体的定义为:</p><p><br/><table cellspacing="1" cellpadding="4" width="80%" align="center"><tbody><tr><td class="code"><pre><br/>namespace&nbsp;Ogre&nbsp;<br/>{<br/>        D3D9RenderSystem*&nbsp;d3dRendPlugin;<br/>        D3D9HLSLProgramFactory*&nbsp;hlslProgramFactory;<p></p><p>        extern&nbsp;"C"&nbsp;void&nbsp;dllStartPlugin(void)&nbsp;throw()<br/>        {<br/>                //&nbsp;Create&nbsp;the&nbsp;DirectX&nbsp;8&nbsp;rendering&nbsp;api<br/>                HINSTANCE&nbsp;hInst&nbsp;=&nbsp;GetModuleHandle(&nbsp;"RenderSystem_Direct3D9.dll"&nbsp;);<br/>                d3dRendPlugin&nbsp;=&nbsp;new&nbsp;D3D9RenderSystem(&nbsp;hInst&nbsp;);<br/>                //&nbsp;Register&nbsp;the&nbsp;render&nbsp;system<br/>                Root::getSingleton().addRenderSystem(&nbsp;d3dRendPlugin&nbsp;);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;create&nbsp;&amp;&nbsp;register&nbsp;HLSL&nbsp;factory<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hlslProgramFactory&nbsp;=&nbsp;new&nbsp;D3D9HLSLProgramFactory();<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HighLevelGpuProgramManager::getSingleton().addFactory(hlslProgramFactory);</p><p>        }</p><p>        extern&nbsp;"C"&nbsp;void&nbsp;dllStopPlugin(void)<br/>        {<br/>                delete&nbsp;d3dRendPlugin;<br/>                delete&nbsp;hlslProgramFactory;<br/>        }<br/>}<br/></p></pre></td></tr></tbody></table><br/></p><p><br/>其中Root::getSingleton().addRenderSystem(&nbsp;d3dRendPlugin&nbsp;)就是将生成的渲染器作为插件,“插”到主引擎中。在主引擎中,对应的部分为:</p><p><br/><table cellspacing="1" cellpadding="4" width="80%" align="center"><tbody><tr><td class="code"><pre><br/>void&nbsp;Root::loadPlugin(const&nbsp;String&amp;&nbsp;pluginName)<br/>        {<br/>                //&nbsp;Load&nbsp;plugin&nbsp;library<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DynLib*&nbsp;lib&nbsp;=&nbsp;DynLibManager::getSingleton().load(&nbsp;pluginName&nbsp;);<br/>                //&nbsp;Store&nbsp;for&nbsp;later&nbsp;unload<br/>                mPluginLibs.push_back(lib);<p></p><p>                //&nbsp;Call&nbsp;startup&nbsp;function<br/>                DLL_START_PLUGIN&nbsp;pFunc&nbsp;=&nbsp;(DLL_START_PLUGIN)lib-&gt;getSymbol("dllStartPlugin");</p><p>                if&nbsp;(!pFunc)<br/>                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,&nbsp;"Cannot&nbsp;find&nbsp;symbol&nbsp;dllStartPlugin&nbsp;in&nbsp;library&nbsp;"&nbsp;+&nbsp;pluginName,<br/>                                "Root::loadPlugins");<br/>                pFunc();</p><p>                if&nbsp;(mIsInitialised)<br/>                {<br/>                        //&nbsp;initialise&nbsp;too<br/>                        DLL_INIT_PLUGIN&nbsp;pFunc&nbsp;=&nbsp;(DLL_INIT_PLUGIN)lib-&gt;getSymbol("dllInitialisePlugin");<br/>                        if&nbsp;(pFunc)<br/>                        {<br/>                                pFunc();<br/>                        }<br/>                }<br/>        }<br/></p></pre></td></tr></tbody></table><br/></p><p><br/>这样就完成了Root::getSingleton().addRenderSystem(&nbsp;d3dRendPlugin&nbsp;)。</p>
页: [1]
查看完整版本: 游戏引擎中的多渲染器的设计与实现(1)