一种让程序支持多渲染器的方法
来源:互联网 发布:linux 查看防火墙端口 编辑:程序博客网 时间:2024/05/18 00:06
一种让程序支持多渲染器的方法
在实际开发中,我们往往倾向于使用新的渲染器API进行图形的绘制,但是担心当部署到目标机器上时,由于硬件和显卡配置的限制而无法使用新的渲染器API。这可真让开发者们头疼。由于不同模型的格式不一样,渲染的方法也不尽相同,再加上渲染器的千变万化,让我们的工作量加大了很多!
一种解决方案是使用游戏引擎来解决问题。本文并不是介绍究竟如何使用这些引擎,而是提出了一种自己的方案,通过为每一个渲染器写一个渲染处理器(render handler)来化解这性能和兼容性的矛盾。
实例:我在开发的时候层考虑如果使用了在OpenGL1.5中提出来的VBO,那么移植到目标机器上时可能会抛弃那些并不支持OpenGL1.5规范的机器(因为可能显卡驱动没有安装等原因而无法支持OpenGL1.5规范)。不过使用glBegin()、glEnd()这样一个顶点一个顶点地添加的确会降低性能,想用VBO来提高性能。怎么办呢?
使用C++的多态机制可以解决问题。根据多次游戏程序编写的经验,我发现一般资源都会经过初始化、使用和回收三个过程,所以我将这三个过程作为纯虚函数提炼出来。成为了IRenderHandler接口。
class IRenderHandler{public: virtual void Init( void ) = 0; virtual void Render( void ) = 0; virtual void Release( void ) = 0;};
IRenderHandler是一个接口类,它抽象了一段渲染过程,子类或实现可以重写这三个纯虚函数,做出不同的渲染效果。
一个很简单的继承例子是,如果应用程序需要DirectX和OpenGL的支持,那么简单地继承这个接口成为两个顶级接口即可。
class IGLRenderHandler: publicIRenderHandler{ }; class IDXRenderHandler: publicIRenderHandler{ };
更具体的情况,想要渲染各个模型,由于各个模型的渲染方式不一样,这样的情况必须再从中继承一个类以适应不同模型的渲染情况。
class MMDRenderHandler: publicIGLRenderHandler{public: virtual ~MMDRenderHandler( void ) { } …… void Init( void ) { …… }protected: QVector<quint16> m_Indices; QVector<Material> m_Materials; QVector<Texture2D> m_Textures; QVector<Bone> m_Bones; QString m_Dir; ……};
对于OpenGL1.1规范和OpenGL1.5规范,再从中继承两个类以实现不同OpenGL规范的渲染。
class MMDRenderHandler_1_1: public MMDRenderHandler, protected QOpenGLFunctions_1_1{ voidInit( void ){……}void Render(void ){……}void Release(void ){……}}class MMDRenderHandler_1_5: public MMDRenderHandler, protected QOpenGLFunctions_1_5{void Init( void){……}void Render(void ){……}void Release(void ){……}};
我使用的是Qt,对于各种OpenGL规范,Qt为我们提供了各种程序集,我和大家一样,无法具体知道每一个函数是从OpenGL什么版本开始提供的,又有哪些函数从OpenGL什么版本开始消失的,还好Qt提供了QOpenGLFunctions_X_X这样的类,通过其保护继承可以让开发者知道在某个版本中OpenGL的函数是否可用,如果不可用,它会报编译错误(OpenGL1.1以及以前的函数除外)。
在Qt中有一个非常方便的函数,可以判断当前系统支持的最高的OpenGL版本,它就是QGLFormat::openGLVersionFlags( )静态函数。我们使用一个指针(或智能指针)保存渲染处理器的地址,像这样:
QScopedPointer<MMDRenderHandler>m_pRenderHandler;
根据系统环境来渲染的代码是:
// 看看OpenGL标准来决定渲染器if ( QGLFormat::openGLVersionFlags( ) &QGLFormat::OpenGL_Version_1_5 ){ m_pRenderHandler.reset( new MMDRenderHandler_1_5 );}else if ( QGLFormat::openGLVersionFlags( )& QGLFormat::OpenGL_Version_1_1 ){ m_pRenderHandler.reset( new MMDRenderHandler_1_1 );}
在开发中,我接触过一游戏引擎,我看到它们对渲染器的封装很深,不过不外乎在渲染时有BeginRender()和EndRender()这样的函数。BeginRender()这样的函数我想意义在于将顶点缓存暴露出来供用户填充数据进来,而EndRender()函数则是结束用户的顶点输入,提交顶点。这里BeginRender()和EndRender()看起来和glBegin()、glEnd()的作用差不多,但由于一些特殊而高效的数据结构使得游戏引擎的执行效率很高。BeginRender()和EndRender()这对函数还包含了对渲染器代码的封装,使得使用跨渲染器的游戏引擎成为可能。
- 一种让程序支持多渲染器的方法
- 让docbook支持颜色的渲染
- WPF一种灵活的程序多国语言支持
- 一种灵活的WPF程序多国语言支持
- 让docbook支持表格行颜色的渲染
- 让vs编写的程序在未安装vs的电脑上使用的一种方法
- 一种简单实现卡通勾边渲染的方法
- 又一种Qt + OpenGL 的离屏渲染方法
- 如何让你的iPhone程序支持多语言环境
- 如何让你的iPhone程序支持多语言环境
- 如何让你的iPhone程序支持多语言环境
- 如何让你的iPhone程序支持多语言环境
- [golang]让golang支持泛型编程的一种方案
- 让你的程序支持插件
- 如何让你的程序支持HA?
- 让程序支持脚本
- 让程序支持gb18030
- 让程序支持UNICODE
- 集成测试
- linux指定程序运行优先级
- 指针
- 漫谈topK 问题
- 面向对象思想--最简单、最容易理解面向对象思想的文章
- 一种让程序支持多渲染器的方法
- TEST
- open新页面数据post过去
- java不同版本特性
- 最近公共祖先LCA:Tarjan算法
- 正确使用Block避免Cycle Retain和Crash
- c++模拟反射机制-方法1
- 浅析Cocos2dx CCProgressTimer 进度条计时器
- JBoss 系列二十三:JBossCache 架构