程序的天空

我的学习心得

导航

Quake2源码分析(5)

Posted on 2008-08-17 02:17  帕托  阅读(1340)  评论(1)    收藏  举报

Ref_gl模块分析:(Ref_soft模块也很类似)

     ref模块负责图形渲染系统的工作,这一节我们来看ref_gl模块。ref模块的输出函数在文件ref.h中,这里不再列出。在gl_rmain.c文件中,我们直接找出ref_gl模块对输出函数的实现:

 

 re.api_version = API_VERSION;                    //API_VERSION为3

 

 re.BeginRegistration = R_BeginRegistration;          //注册作为世界的地图,即设置r_worldmodel=xxx.bsp文件


 re.RegisterModel = R_RegisterModel;          //注册模型,即找到指定名称模型的皮肤,纹理图等


 re.RegisterSkin = R_RegisterSkin;               //找到指定皮肤的图像


 re.RegisterPic = Draw_FindPic;                    //找到指定图像


 re.SetSky = R_SetSky;                    //设置天空,找到表示天空6个面的6张图


 re.EndRegistration = R_EndRegistration;               //释放所有未注册的模型和图像

 

 re.RenderFrame = R_RenderFrame;               //每桢执行的函数,这个函数在后面详述

 

 re.DrawGetPicSize = Draw_GetPicSize;          //得到图像的宽度和高度


 re.DrawPic = Draw_Pic;                         //按指定的宽度和高度画一个图像,下面是它的OpenGL代码:

                    qglBegin (GL_QUADS);               //开始渲染,矩形
                     qglTexCoord2f (gl->sl, gl->tl);               //纹理点,左上
                     qglVertex2f (x, y);                               //顶点,左上
                     qglTexCoord2f (gl->sh, gl->tl);                    //右上
                     qglVertex2f (x+gl->width, y);
                     qglTexCoord2f (gl->sh, gl->th);                    //右下
                     qglVertex2f (x+gl->width, y+gl->height);
                     qglTexCoord2f (gl->sl, gl->th);                    //左下
                     qglVertex2f (x, y+gl->height);
                     qglEnd ();


 re.DrawStretchPic = Draw_StretchPic;               //也是画一个拉伸的图片,和上个函数很相似


 re.DrawChar = Draw_Char;               //画一个字符,本质上根据字符序号取得相应的纹理坐标(所有字符是一个大的纹理),然后再画这个纹理


 re.DrawTileClear = Draw_TileClear;          //画一个64*64的位图以填充屏幕


 re.DrawFill = Draw_Fill;                    //以一种颜色填充一个矩形(顶点指定颜色,不用纹理)


 re.DrawFadeScreen= Draw_FadeScreen;               //开启颜色混合,画一个混合黑白颜色的矩形

 

 re.DrawStretchRaw = Draw_StretchRaw;          //对原图像数据进行处理构造新的纹理,画出这个纹理

 

 re.Init = (int (__cdecl *)(void *,void *))R_Init;          //初始化整个ref系统,设置它的配置参数和全局变量,初始化纹理等


 re.Shutdown = R_Shutdown;                    //释放模型,图像和其他资源

 

 re.CinematicSetPalette = R_SetPalette;               //设置调色板r_rawpalette,并调用GL_SetTexturePalette( r_rawpalette );设置纹理调色板


 re.BeginFrame = R_BeginFrame;               //开始桢:处理日志改变,进入2D模式,处理缓存改变,纹理模式改变,清空屏幕


 re.EndFrame = GLimp_EndFrame;               //结束桢

 

 re.AppActivate = GLimp_AppActivate;          //根据激活状态设置活动窗口

 

 追踪R_RenderFrame函数(渲染一桢):

1.R_RenderView( fd );      //渲染整个视觉空间


           R_PushDlights ();  //对每个动态光源,递归设置结点表面的动态光标记位,如果结点不在动态光照范围内则结束递归


           R_SetupFrame ();  //设置变换矩阵,设置viewcluster,如果观察点在某个叶子结点中,设置为该叶子结点的cluster


           R_SetFrustum ();  //设置视觉空间的4个侧面


           R_SetupGL (); //计算视口,投影矩阵,视点,世界变换


           R_MarkLeaves (); // done here so we know if we're in water
            标记叶子结点,首先找到当前的r_viewcluster的PVS,
                 对世界空间中的每个叶子结点
                       如果叶子结点的cluster在当前PVS中,
                            设置结点的visframe(表示可见)
                            继续向父结点循环(父结点也可能可见)


           R_DrawWorld ();            //画整个世界空间
                      R_RecursiveWorldNode (r_worldmodel->nodes);
                                 1.如果是可见的叶子结点,标记结点的每个表面为可见(visframe),返回
                                 2.如果是可见的分割结点,递归调用R_RecursiveWorldNode前端子结点
                                  处理结点的表面
                                  递归调用R_RecursiveWorldNode后端子结点
                      画纹理,光图,天空盒子


           R_DrawEntitiesOnList (); //对每个实体,画它的每个模型(三种:alias,brush,sprite)


           R_RenderDlights ();  //画每个动态光(一个球体)


           R_DrawParticles ();  //画粒子系统的每个粒子


           R_DrawAlphaSurfaces (); //画透明表面和水表面


           R_Flash();


2.R_SetLightLevel ();  //设置lightlevel值(光照度)


3.R_SetGL2D ();  //设置2D空间

 

总结:

          至此,整个渲染过程结束,通过前面几节,我们已经走完了quake2引擎当中每一桢需要完成的工作,当然这个框架相当的粗糙。值得注意的是quake2引擎针对FPS游戏做了很大程度的优化,特定的设置被写如了代码中,因为游戏的细节比较复杂,我们对quake2引擎框架的概述就分析到这里,以后有时间的话我会讲quake2游戏中的一些细节分析写出来。