2015年1月13日星期二(11-1深度缓存和可见性简介)


新的一年,开始新的篇章,终于进入第11章了。必须首要搞这个。争取今年搞完,我也相信,会对3D学习不是浪费时间。而是内力提升。

在以前,用画家算法进行多边形排序,即根据渲染列表中的每个多边形的平均、最小或最大值进行排序,然后,再从后到前的顺序绘制多边形。

大多数情况下,是正确的。但是,在多边形相互贯通、包含大小各异的几何体时,画家算法可能失效,

引入Z缓存(即像素级画家算法):将对像素进行排序,

算法如下:

For(渲染列表中的每个多边形) begin

 1,对其进行光栅化,生成xi,yi,zi,

For(每组xi,yi,zi)

2,if( zi < zbuffer[xi,yi], then

 Zbuffer[xi,yi]= zi,然后将像素显示到屏幕上,Plot(xi,yi).

End for

 

获取多边形的Z值方法:

根据多边形所在的平面;ax+by+cz+d=0.求得z值。

然后可以进行插值运算。

 

Z缓存的问题:

上述三角形的(x,y,z)是3D空间推导进行,即世界做表空间或相机坐标空间,而Z缓冲是在屏幕空间的投影坐标(x_screen,y_screen),而x_screen = d * x/z; y_screen= d * y /z,可知,Z值不是线性的,而1/z是线性的。

首先定义z缓存的变量和数据结构

//为z缓存数据结构定义的常量

#define  ZBUFFER_ATTR_16BIT                     16

#define  ZBUFFER_ATTR_32BIT                     32

 

//Z缓存数据结构

typedef struct ZBUFFERV1_TYP

{

    int               attr;             //z缓存的属性,位或位

    UCHAR    *        zbuffer;     //指向Z缓存的指针

    int               width;            //z缓存的宽度,单位为像素

    int               height;           //z缓存的高度,单位为像素

    int               sizeq;            //实际的四元组大小(每个四元组为个字节)

} ZBUFFERV1, *ZBUFFERV1_PTR;

 

 

创建z缓存

 

 

int DDRAW_LIUSHUIXIAN_TEXTURE::Create_Zbuffer(ZBUFFERV1_PTRzb, int width, int height, int attr)

{

    //指针zb是否有效

    if(!zb )

         return0;

 

    //是否已经给zb指向的ZBUFFERV1分配了内存

    if(zb->zbuffer)

         free(zb->zbuffer);

 

    //设置字段

    zb->width                              =width;

    zb->height                             =height;

    zb->attr                           =attr;

 

    //z缓存是位的还是位的

    if(attr & ZBUFFER_ATTR_16BIT)

    {

         //计算四元组数

         zb->sizeq                          =width * height/ 2;

 

         //分配内存

         if(( zb->zbuffer= ( UCHAR * ) malloc(width * height* sizeof( SHORT) ) ) )

             return1;

         else

             return0;

    }

    else

    if(attr & ZBUFFER_ATTR_32BIT)

    {

         //计算四元组数

         zb->sizeq                          =width * height;

 

         //分配内存

         if(( zb->zbuffer= ( UCHAR * ) malloc(width * height* sizeof( INT) ) ) )

             return1;

         else

             return0;

    }

    else

         return0;

}

 

每次写入一个32位UINT值的方式填充/设置内存

void ddraw_math::Mem_Set_QUAD( void* dest, USHORTdata, int count )

{

    _asm

    {

         movedi, dest     ;

         movecx, count    ;

         moveaxdata    ;

         repstosd         ;

    }

}

清空/填充z缓存

 

 

void DDRAW_LIUSHUIXIAN_TEXTURE::Clear_Zbufffer(ZBUFFERV1_PTRzb, UINT data)

{

    ddraw_mathmath;

    math.Mem_Set_QUAD( ( void* ) zb->zbuffer,data, zb->sizeq );

}

 

删除z缓存,

 

int DDRAW_LIUSHUIXIAN_TEXTURE::Delete_Zbuffer(ZBUFFERV1_PTRzb)

{

    if(zb )

    {

         //释放内存

         if(zb->zbuffer)

             free(zb->zbuffer);

 

         //清除内存中的数据

         memset(( void * ) zb,0, sizeof( ZBUFFERV1) );

         return1;

    }

    else

         return0;

}

 

首先,更新恒定Shader处理函数

以GouraudShader处理函数,不进行RGB颜色插值,每个像素都使用相同的颜色,并将对某个颜色分量进行插值的代码改为对Z值进行插值的代码。

 

 

void ddraw_math::Draw_Triangle_2DZB_16(                  POLYF4DV2_PTR                  face,         //指向多边形面的指针

                                                             UCHAR                     *    _dest_buffer,//指向视频缓存的指针

                                                             int                           mem_pitch,   //每行占用多少字节(,640

                                                             UCHAR                     *    _zbuffer,    //指向z缓存的指针

                                                             int                           zpitch )

中,把U,I坐标改为Z坐标,其余没变。

 

对于Gouraud shader,只需加入z值的代码即可。

 

 

void ddraw_math::Draw_Gouraud_TriangleZB16( POLYF4DV2_PTR    face,        //指向多边形的指针

                                                                  UCHAR    *       _dest_buffer,//指向视频缓存的指针

                                                                  int               mem_pitch, //每行占据的字节数

                                                                  UCHAR                     *    _zbuffer,    //指向z缓存的指针

                                                                                                                                        int                            zpitch ) //z缓存每行占用的字节数

 

 

对于支持固定着色的纹理映射函数。,也是插入Z代码,并Z缓存比较。

 

void ddraw_math::Draw_Textured_TriangleZB16(    POLYF4DV2_PTR     face,        //指向多边形的指针

                                                                  UCHAR    *       _dest_buffer,//指向视频缓存的指针

                                                                  int               mem_pitch, //每行占据的字节数

                                                                  UCHAR        *   _zbuffer,    //指向z缓存的指针

                                                                                                                                        int               zpitch ) //z缓存每行占用的字节数

 

对于支持恒定着色的纹理映射函数,更新Z缓冲将通过Z缓冲的绘制

 

void ddraw_math::Draw_Textured_TriangleFSZB16POLYF4DV2_PTR     face,        //指向多边形的指针

                                                                  UCHAR    *       _dest_buffer,//指向视频缓存的指针

                                                                  int               mem_pitch, //每行占据的字节数

                                                                  UCHAR        *   _zbuffer,    //指向z缓存的指针

                                                                                                                                        int               zpitch) //z缓存每行占用的字节数

对于接下来进行更新渲染列表函数,进行绘制的各个路径。

 

void DDRAW_LIUSHUIXIAN_TEXTURE::   Draw_RENDERLIST4DV2_SolidZB16(ddraw_math math2,RENDERLIST4DV2_PTR rend_list,UCHAR * video_buffer,int lpitch,

                                                                          UCHAR    *                 zbuffer,

                                                                          int                        zpitch)

{

    POLYF4DV2                 face;

 

    for(int poly =0; poly < rend_list->num_polys; poly++)

    {

         //获得当前多边形

         POLYF4DV2_PTR         curr_poly                 = rend_list->poly_ptrs[poly];

 

 

         //当且仅当多边形没有被剔除或者裁剪掉,同时处于活动状态且可见时,才对其进行变换)

         if(!( curr_poly->state& POLY4DV2_STATE_ACTIVE ) ||

             ( curr_poly->state& POLY4DV2_STATE_CLIPPED ) ||

             ( curr_poly->state& POLY4DV2_STATE_BACKFACE ) )

             continue;    //进入下一个多边形

 

         //先测试纹理,

         if(rend_list->poly_ptrs[poly]->attr& POLY4DV2_ATTR_SHADE_MODE_TEXTURE )

         {

             face.tvlist[0].x                    =( int ) rend_list->poly_ptrs[poly]->tvlist[0].x;

             face.tvlist[0].y                   = ( int) rend_list->poly_ptrs[poly]->tvlist[0].y;

             face.tvlist[0].z                   = ( int) rend_list->poly_ptrs[poly]->tvlist[0].z;

             face.tvlist[0].u0                  = ( int) rend_list->poly_ptrs[poly]->tvlist[0].u0;

             face.tvlist[0].v0                  = ( int) rend_list->poly_ptrs[poly]->tvlist[0].v0;

 

             face.tvlist[1].x                   = ( int) rend_list->poly_ptrs[poly]->tvlist[1].x;

             face.tvlist[1].y                   = ( int) rend_list->poly_ptrs[poly]->tvlist[1].y;

             face.tvlist[1].z                   =( int ) rend_list->poly_ptrs[poly]->tvlist[1].z;

             face.tvlist[1].u0                  = ( int) rend_list->poly_ptrs[poly]->tvlist[1].u0;

             face.tvlist[1].v0                  = ( int) rend_list->poly_ptrs[poly]->tvlist[1].v0;

 

             face.tvlist[2].x                   = ( int) rend_list->poly_ptrs[poly]->tvlist[2].x;

             face.tvlist[2].y                   = ( int) rend_list->poly_ptrs[poly]->tvlist[2].y;

             face.tvlist[2].z                   = ( int) rend_list->poly_ptrs[poly]->tvlist[2].z;

             face.tvlist[2].u0                  = ( int) rend_list->poly_ptrs[poly]->tvlist[2].u0;

             face.tvlist[2].v0                  = ( int) rend_list->poly_ptrs[poly]->tvlist[2].v0;

 

             face.texture                       =rend_list->poly_ptrs[poly]->texture;

 

             if(rend_list->poly_ptrs[poly]->attr& POLY4DV2_ATTR_SHADE_MODE_CONSTANT )

             {

                  math2.Draw_Textured_TriangleZB16(& face, video_buffer,lpitch, zbuffer,zpitch );

             }

             else

             {

                  face.lit_color[0]              = rend_list->poly_ptrs[poly]->lit_color[0];

 

                  math2.Draw_Textured_TriangleFSZB16(& face, video_buffer,lpitch, zbuffer,zpitch );

             }

 

         }

         else

             if(( rend_list->poly_ptrs[poly]->attr& POLY4DV2_ATTR_SHADE_MODE_FLAT )

                  || ( rend_list->poly_ptrs[poly]->attr& POLY4DV2_ATTR_SHADE_MODE_CONSTANT ) )

             {

                  //使用固定着色

                  face.lit_color[0]              = rend_list->poly_ptrs[poly]->lit_color[0];

 

                  //设置顶点坐标

                  face.tvlist[0].x               =( float ) rend_list->poly_ptrs[poly]->tvlist[0].x;

                  face.tvlist[0].y               =( float ) rend_list->poly_ptrs[poly]->tvlist[0].y;

                  face.tvlist[0].z               =( float ) rend_list->poly_ptrs[poly]->tvlist[0].z;

 

                  face.tvlist[1].x               =( float ) rend_list->poly_ptrs[poly]->tvlist[1].x;

                  face.tvlist[1].y               =( float ) rend_list->poly_ptrs[poly]->tvlist[1].y;

                  face.tvlist[1].z               =( float ) rend_list->poly_ptrs[poly]->tvlist[1].z;

 

                  face.tvlist[2].x               =( float ) rend_list->poly_ptrs[poly]->tvlist[2].x;

                  face.tvlist[2].y               =( float ) rend_list->poly_ptrs[poly]->tvlist[2].y;

                  face.tvlist[2].z               =( float ) rend_list->poly_ptrs[poly]->tvlist[2].z;

 

                  math2.Draw_Triangle_2DZB_16(& face, video_buffer,lpitch, zbuffer,zpitch );

 

 

                 

             }

             else

                  if( rend_list->poly_ptrs[poly]->attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD)

                  {

                      face.tvlist[0].x                   =( float ) rend_list->poly_ptrs[poly]->tvlist[0].x;

                      face.tvlist[0].y                   =( float ) rend_list->poly_ptrs[poly]->tvlist[0].y;

                      face.tvlist[0].z                   =( float ) rend_list->poly_ptrs[poly]->tvlist[0].z;

                      face.lit_color[0]                  =  rend_list->poly_ptrs[poly]->lit_color[0];

 

                      face.tvlist[1].x                   =( float ) rend_list->poly_ptrs[poly]->tvlist[1].x;

                      face.tvlist[1].y                   =( float ) rend_list->poly_ptrs[poly]->tvlist[1].y;

                      face.tvlist[1].z                   =( float ) rend_list->poly_ptrs[poly]->tvlist[1].z;

                      face.lit_color[1]                  =  rend_list->poly_ptrs[poly]->lit_color[1];

 

                      face.tvlist[2].x                   =( float ) rend_list->poly_ptrs[poly]->tvlist[2].x;

                      face.tvlist[2].y                   =( float ) rend_list->poly_ptrs[poly]->tvlist[2].y;

                      face.tvlist[2].z                   =( float ) rend_list->poly_ptrs[poly]->tvlist[2].z;

                      face.lit_color[2]                  =  rend_list->poly_ptrs[poly]->lit_color[2];

 

                      math2.Draw_Gouraud_TriangleZB16(& face, video_buffer,lpitch, zbuffer,zpitch );

                  }

 

 

 

 

    }

 

 

}

 

优化部分基本过时,主要看算法,看看例子如何运行。

 

首先定义了个庞大的物体,(因为要Z缓冲排序,所以物体较多。)

#define  CAM_DECEL                 0.25

#define  MAX_SPEED                 20

#define  NUM_OBJECTS               5

#define  NUM_SCENE_OBJECTS     500

#define  UNIVERSE_RADIUS           2000

 

摄像机改变位置

POINT4D  cam_pos    ={0,0,0,1};

物体名和当前物体序号

char *        object_filenames[NUM_OBJECTS]      ={ "cube_flat_01.cob", "cube_gouraud_01.cob",

"cube_flat_textured_01.cob","sphere02.cob","sphere03.cob",};

 

int                                                  curr_object  =2;

每个物体的位置

POINT4D           scene_objects[NUM_SCENE_OBJECTS];

摄像机速度和Z缓冲设置。

 

float             cam_speed         =0;

ZBUFFERV1                                   zbuffer;

 

在Game_Init()中,

设置摄像机参数

 

    liushuixian.Init_CAM4DV1( * math,&cam,      // the camera object

         CAM_MODEL_EULER,// the euler model

         &cam_pos // initial camera position

         &cam_dir // initial camera angles

         &cam_target,      // no target

         15.0,      // near and farclipping planes

         12000.0,

         120.0,      // field ofview in degrees

         SCREEN_WIDTH,   // size of finalscreen viewport

                                            SCREEN_HEIGHT);

加载物体

    for(int index_obj= 0; index_obj < NUM_OBJECTS;index_obj++ )

    {

 

         liushuixian_texture.Load_OBJECT4DV2_COB( * math,matiGroup, &obj_array[index_obj], object_filenames[index_obj], 

         &vscale, &vpos, &vrot, VERTEX_FLAGS_SWAP_YZ|

         VERTEX_FLAGS_TRANSFORM_LOCAL); 

                                           }

 

设置当前物体

 

 

    curr_object  = 2;

    obj_work = & obj_array[curr_object];

 

加载场景

 

    liushuixian_texture.Load_OBJECT4DV2_COB( * math,matiGroup, &obj_scene,"cube_gouraud_01.cob"

         &vscale, &vpos, &vrot, VERTEX_FLAGS_SWAP_YZ|

         VERTEX_FLAGS_TRANSFORM_LOCAL); 

 

看了一下DEMO的例子效果,感觉不错,所以把4个灯光全加上

white.rgba = _RGBA32BIT(255,255,255,0);

    gray.rgba  = _RGBA32BIT(100,100,100,0);

    black.rgba = _RGBA32BIT(0,0,0,0);

    red.rgba   = _RGBA32BIT(255,0,0,0);

    green.rgba = _RGBA32BIT(0,255,0,0);

    blue.rgba  = _RGBA32BIT(0,0,255,0) ;

 

    light.Init_Light_LIGHTV2( * math,lightGroup,AMBIENT_LIGHT_INDEX,LIGHTV2_STATE_ON, LIGHTV2_ATTR_AMBIENT,gray, black,black, NULL,NULL, 0, 0, 0, 0, 0, 0 );

   

    VECTOR4D dlight_dir        = { -1, 0, -1, 1 };

    light.Init_Light_LIGHTV2( * math,lightGroup,INFINITE_LIGHT_INDEX,LIGHTV2_STATE_ON, LIGHTV2_ATTR_INFINITE,black, gray,black, NULL,& dlight_dir, 0, 0, 0, 0, 0, 0 );

 

    VECTOR4D plight_pos        = { 0, 200, 0, 1 };

    light.Init_Light_LIGHTV2( * math,lightGroup,POINT_LIGHT_INDEX,LIGHTV2_STATE_ON, LIGHTV2_ATTR_POINT,black, green,black, & plight_pos,NULL, 0, 0.002, 0, 0, 0, 1 );

 

    VECTOR4D slight2_dir       = { -1, 0, -1, 1 };

    VECTOR4D slight2_pos       = { 0, 1000, 0, 1 };

    light.Init_Light_LIGHTV2( * math,lightGroup,SPOT_LIGHT2_INDEX,LIGHTV2_STATE_ON, LIGHTV2_ATTR_SPOTLIGHT2,black, red,black, & slight2_pos,& slight2_dir, 0, 0.001, 0, 0, 0, 1 );

 

 

设置Z缓冲

 

      liushuixian_texture.Create_Zbuffer(& zbuffer, SCREEN_WIDTH,SCREEN_HEIGHT, ZBUFFER_ATTR_32BIT);

 

在每帧中,设定灯光旋转

    staticfloat plight_ang= 0, slight_ang = 0;

物体旋转

    staticfloat x_ang= 0, y_ang = 0, z_ang= 0;

Z缓冲模式

static int z_buffer_mode                 =1;

忘了背面消除,这里补上。

 

int DDRAW_LIUSHUIXIAN_TEXTURE::Cull_OBJECT4DV2( OBJECT4DV2_PTRobj, CAM4DV1_PTRcam, int cull_flags,ddraw_mathmath )

{

    //将物体包围球球心变换为相机坐标

    POINT4D                                sphere_pos;           //用于存储包围球球心变换后的坐标

    //对点进行变换

    math.Mat_Mul_VECTOR4D_4X4( & obj->world_pos,& cam->mcam,& sphere_pos );

    //根据剔除标记对物体执行剔除操作

    if(cull_flags & CULL_OBJECT_Z_PLANE)

    {

         //cull only based on z clipping planes

 

         //test far plane

         if( ((sphere_pos.z- obj->max_radius[obj->curr_frame]) > cam->far_clip_z)||

             ((sphere_pos.z + obj->max_radius[obj->curr_frame])< cam->near_clip_z))

         {

             SET_BIT(obj->state, OBJECT4DV2_STATE_CULLED);

             return(1);

         } //end if

 

    } //end if

 

    if(cull_flags & CULL_OBJECT_X_PLANE)

    {

         //cull only based on x clipping planes

         //we could use plane equations, but simple similar triangles

         //is easier since this is really a 2D problem

         //if the view volume is 90 degrees the the problem is trivial

         //buts lets assume its not

 

         //test the the right and left clipping planes against the leftmost and rightmost

         //points of the bounding sphere

         floatz_test = (0.5)*cam->viewplane_width*sphere_pos.z/cam->view_dist;

 

         if( ((sphere_pos.x-obj->max_radius[obj->curr_frame])> z_test) || // right side

             ((sphere_pos.x+obj->max_radius[obj->curr_frame])< -z_test) )  // left side, notesign change

         {

             SET_BIT(obj->state, OBJECT4DV2_STATE_CULLED);

             return(1);

         } //end if

    } //end if

 

 

    if(cull_flags & CULL_OBJECT_Y_PLANE)

    {

 

         //test the the right and left clipping planes against the leftmost and rightmost

         //points of the bounding sphere

         floatz_test = (0.5)*cam->viewplane_height*sphere_pos.z/cam->view_dist;

 

         if( ((sphere_pos.y-obj->max_radius[obj->curr_frame])> z_test) || // right side

             ((sphere_pos.y+obj->max_radius[obj->curr_frame])< -z_test) )  // left side, notesign change

         {

             SET_BIT(obj->state, OBJECT4DV2_STATE_CULLED);

             return(1);

         } //end if

    } //end if

 

    return( 0 );

}

 

根据Z缓冲,按照Z的大小不同图示如下:



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值