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游戏中的一些细节分析写出来。
浙公网安备 33010602011771号