对于高性能的3D游戏显示,目前在世界上流行的就两套API,一套是OpenGL,一套是微软的D3D。由于OpenGL跨平台的特性,对于第二人生来说,是没有别的选择了。那么在第二人生里渲染管道到底是怎么样调用OpenGL函数的呢?又有什么特别的方式可以让调用OpenGL更加方便呢?由于OpenGL并不是基于C++的接口,所以在第二人生里就肯定先把这些API组织成类的方式,才会更方便使用。下面就来仔细地分析类LLGLImmediate,它的声明如下: #001 #002 class LLGLImmediate #003 { #004 public: #005 LLGLImmediate(); #006 下面函数通过当前矩阵乘以参数构造的平移矩阵实现平移功能。 #007 void translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z); 下面函数把当前矩阵压入到栈里,避免当前的操作对当前的矩阵下一次使用有影响。 #008 void pushMatrix(); 下面函数把栈顶里的矩阵取出来,恢复前面保存的矩阵。 #009 void popMatrix(); 下面函数指明像素混合的方式。 #010 void blendFunc(GLenum sfactor, GLenum dfactor); 下面函数指明一帧图片渲染开始。 #011 void start(); 下面函数指明一帧图片渲染结束。 #012 void stop(); 下面函数指明OPENGL一帧图片渲染生效。 #013 void flush(); #014 下面两个函数指明OPENGL一帧图片渲染开始和结束。 #015 void begin(const GLuint& mode); #016 void end(); 下面的函数都是指明顶点。 #017 void vertex2i(const GLint& x, const GLint& y); #018 void vertex2f(const GLfloat& x, const GLfloat& y); #019 void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z); #020 void vertex2fv(const GLfloat* v); #021 void vertex3fv(const GLfloat* v); #022 下面的函数指明纹理坐标位置。 #023 void texCoord2i(const GLint& x, const GLint& y); #024 void texCoord2f(const GLfloat& x, const GLfloat& y); #025 void texCoord2fv(const GLfloat* tc); #026 下面的函数都是指明当前顶点的颜色。 #027 void color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a); #028 void color4f(const GLfloat& r, const GLfloat& g, const GLfloat& b, const GLfloat& a); #029 void color4fv(const GLfloat* c); #030 void color3f(const GLfloat& r, const GLfloat& g, const GLfloat& b); #031 void color3fv(const GLfloat* c); #032 void color4ubv(const GLubyte* c); #033 #034 // switch clever mode GL immediate rendering on or off. Setting to true builds #035 // client arrays manually, setting to false passes through the GL immediate mode #036 // commands to the GL implementation. Controllable by the RenderUseCleverUI #037 // debug setting. #038 // *NOTE: I have measured that this has about a 9% performance cost (0.6ms) for the #039 // Render/UI fasttimer vs the old #if CLEVER compile time switch. Dave Parks and I #040 // agreed that this was acceptable at the time due to it enabling better regression #041 // testing for QA. #042 // -Brad 下面指明是否使用顶点缓冲区来优化对API的操作,主要减少对API的操作,这样可以提高速度。 #043 void setClever(bool do_clever); #044 #045 typedef struct Vertex #046 { #047 GLfloat v[3]; #048 GLubyte c[4]; #049 GLfloat uv[2]; #050 }; #051 #052 private: #053 static bool sClever; #054 #055 U32 mCount; #056 U32 mMode; 自己定义的顶点缓冲区,以便保存数据,最后一次性里设置到OPENGL里。 #057 Vertex mBuffer[4096]; #058 }; 通过上面的函数,学会了怎么样封装OPENGL的API函数,并且提出了使用缓冲区的方法来提高渲染速度。在第二人生渲染管道里会不断地调用这个类的函数来操作OPENGL,这样比较容易维护,也达到更加容易使用的目的,并且全局只一个渲染对象。