2014年2月14日星期五(DEMO7-4,3D坦克)

来源:互联网 发布:运动水杯推荐 知乎 编辑:程序博客网 时间:2024/04/28 13:37

先看区别:

1, 相机可旋转了,上个例子是固定相机

2, 进行的不是背面消除,而是物体剔除

3, 渲染的不是单个物体,而是多个物体的渲染列表。列表中,是单物体多位置

先看物体剔除操作,

物体剔除是的位置在世界坐标系之后,在背面消除之前,即流水线目前是这样子的:

模型坐标->局部坐标到世界坐标转换->世界坐标->物体消除->背面消除->世界坐标到相机坐标转换->相机坐标->投影坐标->屏幕坐标

 

其中物体剔除,可以按照包围球测试,判断是否在视景体内,(当然,包围球测试并非一直有效,或许要用包围盒或者其它几何体)

有三种情况

1, 物体完全在视景体之外

2, 物体完全在视景体之内

3, 物体部分在视景体之内

包围球半径是物体包含顶点离物体中心的最远距离,

为计算方便,包围球在相机坐标中转换,相机设定为90度。球取6个点,分别与正负X,正负Y轴,正负Z轴的平行点,测试目的是为了排除整个球体,

判断点p(X,Y,Z)是否位于视景体外的通用规则为

if( (z>far_z ) || ( z<near_z ) ||   //远近裁剪面

( fabs(x)<z ) ||                       //左右裁剪面

( fabs(y) <z ) )                       //上下裁剪面

{

//物体不在视景体内

}

先定义几个剔除标志,根据各个轴

 

 

//剔除标志

#define CULL_OBJECT_X_PLANE                     0x0001            //根据左右裁剪面进行剔除

#define CULL_OBJECT_Y_PLANE                     0x0002            //根据上下裁剪面进行剔除

#define CULL_OBJECT_Z_PLANE                     0x0004            //根据远近裁剪面进行剔除

#define CULL_OBJECT_XYZ_PLANES              ( CULL_OBJECT_X_PLANE |CULL_OBJECT_Y_PLANE | CULL_OBJECT_Z_PLANE )

 

 

int ddraw_liushuixian::Cull_OBJECT4DV1( OBJECT4DV1_PTR obj, CAM4DV1_PTR cam, int cull_flags,ddraw_math math )

{

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

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) > cam->far_clip_z) ||

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

    {

        SET_BIT(obj->state, OBJECT4DV1_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

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

 

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

        ((sphere_pos.x+obj->max_radius) < -z_test) )  // left side, note sign change

    {

        SET_BIT(obj->state, OBJECT4DV1_STATE_CULLED);

        return(1);

    } // end if

} // end if

 

if (cull_flags & CULL_OBJECT_Z_PLANE)

{

    // cull only based on z clipping planes

 

    // test far plane

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

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

    {

        SET_BIT(obj->state, OBJECT4DV1_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

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

 

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

        ((sphere_pos.y+obj->max_radius) < -z_test) )  // left side, note sign change

    {

        SET_BIT(obj->state, OBJECT4DV1_STATE_CULLED);

        return(1);

    } // end if

} // end if

 

return ( 0 );

}

现在,可以逐步进行,

首先定义了一行物体的个数和物体间距

 

// object defines

#define NUM_OBJECTS     2       // number of objects on a row

#define OBJECT_SPACING  250     // spacing between objects

 

设置摄像机位置

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

物体不放缩

VECTOR4D vscale={1.0,1.0,1.0,1},

因为要渲染一群坦克,所以用渲染列表

RENDERLIST4DV1         render_list;

 

在Game_Init()中,初始化发生改变如下:

将远切面改为1000

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

                  CAM_MODEL_EULER, // euler camera model

                  &cam_pos,  // initial camera position

                  &cam_dir,  // initial camera angles

                  NULL,      // no initial target

                  50.0,      // near and far clipping planes

                  1000.0,

                  90.0,      // field of view in degrees

                  WINDOW_WIDTH,   // size of final screen viewport

                  WINDOW_HEIGHT);

                 

加载坦克模型

         liushuixian.Load_OBJECT4DV1_PLG( & obj, "tank1.plg", & vscale, & vpos, & vrot );

设定模型

         obj.world_pos.x                                                                      = 0;

         obj.world_pos.y                                                                      = 0;

         obj.world_pos.z                                                              = 400;

 

在Game_Main()中,每帧先重置列表

liushuixian.Reset_RENDERLIST4DV1( &render_list);

重置角度

 

 

         ang_x                                                                     = 0;

         ang_y                                                                     = 1;

         ang_z                                                                     = 0;

 

通过按键控制摄像机朝向

if ( KEYDOWN( VK_DOWN))

         {

                  cam.dir.x                                              += 1;

         }

         else

         if ( KEYDOWN( VK_UP))

         {

                  cam.dir.x                                              -= 1;

         }

 

         if ( KEYDOWN( VK_LEFT))

         {

                  cam.dir.y                                              += 1;

         }

         else

         if ( KEYDOWN( VK_RIGHT))

         {

                  cam.dir.y                                              -= 1;

         }

 

旋转角度矩阵

mrot =  math->Build_XYZ_Rotation_MATRIX4x4(  ang_x, ang_y, ang_z );

上个DEMO,位置是这么设定的

 

         liushuixian.Transform_OBJECT4DV1( &obj, &mrot, TRANSFORM_LOCAL_ONLY, 1, * math );

 

    现在由于是列表,

         for ( int x = - NUM_OBJECTS / 2; x < NUM_OBJECTS / 2; x++ )

         {

                  for ( int z = - NUM_OBJECTS / 2; z < NUM_OBJECTS / 2; z++)

                  {

                          liushuixian.Reset_OBJECT4DV1( & obj );

                          //设置物体位置

                          obj.world_pos.x                                   = x * OBJECT_SPACING + OBJECT_SPACING / 2;

                          obj.world_pos.y                                   = 0;

                          obj.world_pos.z                           = 500 + z * OBJECT_SPACING + OBJECT_SPACING / 2;

//判断是否物体消除,没有的话,则转到世界坐标系,并插入渲染列表

         if ( ! liushuixian.Cull_OBJECT4DV1( & obj, & cam, CULL_OBJECT_XYZ_PLANES))

                          {

                                   liushuixian.Model_To_World_OBJECT4DV1( & obj, * math );

                                   liushuixian.Insert_POLYF4DV1_RENDERLIST4DV1( & render_list, & obj );

                          }

接下来,改动的,还有个消除列表背面,这里没有,要加上,

 

void ddraw_liushuixian::Remove_Backfaces_RENDERLIST4DV1(RENDERLIST4DV1_PTR rend_list, CAM4DV1_PTR cam, ddraw_math math )

{

 

         // process each poly in mesh

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

         {

                  // acquire polygon

                  POLYF4DV1_PTR curr_poly = rend_list->poly_ptrs[poly];

 

                  // is this polygon valid?

                  // test this polygon if and only if it's not clipped, not culled,

                  // active, and visible and not 2 sided. Note we test for backface in the event that

                  // a previous call might have already determined this, so why work

                  // harder!

                  if ( ( curr_poly == NULL) ||

                          !(curr_poly->state & POLY4DV1_STATE_ACTIVE) ||

                          (curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||

                          (curr_poly->attr  & POLY4DV1_ATTR_2SIDED)    ||

                          (curr_poly->state & POLY4DV1_STATE_BACKFACE) )

                  {

                         

                          continue;

                  }

 

        

 

                  VECTOR4D u, v, n;

 

                  // build u, v

                  math.VECTOR4D_Build(curr_poly->tvlist[0],curr_poly->tvlist[1], &u);

                  math.VECTOR4D_Build(curr_poly->tvlist[1],curr_poly->tvlist[2], &v);

 

                  // compute cross product

                  math.VECTOR4D_CROSS(&u, &v, &n);

 

                  // now create eye vector to viewpoint

                  VECTOR4D view;

                  math.VECTOR4D_Build(&curr_poly->tvlist[0], &cam->pos, &view);

 

                  // and finally, compute the dot product

                  float dp = math.VECTOR4D_DOT(&n, &view);

 

                  // if the sign is > 0 then visible, 0 = scathing, < 0 invisible

                  if (dp <= 0.0 )

                          SET_BIT(curr_poly->state, POLY4DV1_STATE_BACKFACE);

 

        

         } // end for poly

         fclose(fp);

} // end Remove_Backfaces_OBJECT4DV1

 

 

剩下部分都改成列表

        

         liushuixian.Build_CAM4DV1_Matrix_Euler( *math, & cam, CAM_ROT_SEQ_ZYX );

         liushuixian.Remove_Backfaces_RENDERLIST4DV1( & render_list, &cam, * math );

        

         liushuixian.World_To_Camera_RENDERLIST4DV1(  *math, &render_list, & cam );

         liushuixian.Camera_To_Perspective_RENDERLIST4DV1( &render_list, & cam );

         liushuixian.Perspective_To_Screen_RENDERLIST4DV1( &render_list, & cam );

        

         ddraw->DDraw_Lock_Back_Surface();

         liushuixian.Draw_RENDERLIST4DV1_Wire16( *math, & render_list, ddraw->getbackbuffer(), ddraw->getbacklpitch() );

 

 

加上个将物体插入列表中的函数,

 

int ddraw_liushuixian::Insert_OBJECT4DV1_RENDERLIST4DV1( RENDERLIST4DV1_PTR rend_list, OBJECT4DV1_PTR obj,int insert_local /* = 0 */ )

{

         if ( ! ( obj->state & OBJECT4DV1_STATE_ACTIVE ) ||

                  ( obj-> state & OBJECT4DV1_STATE_CULLED ) ||

                  ! ( obj->state & OBJECT4DV1_STATE_VISIBLE))

         {

                  return ( 0 );

         }

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

         {

                  POLY4DV1_PTR              curr_poly                             = & obj->plist[poly];

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

                             ( curr_poly->state & POLY4DV1_STATE_CLIPPED) ||

                             ( curr_poly->state & POLY4DV1_STATE_BACKFACE ))

                         

                  {

                          continue;

                  }

                  POINT4D_PTR                          vlist_old                              = curr_poly->vlist;

                  if ( insert_local )

                  {

                          curr_poly->vlist                                             = obj->vlist_local;

 

                  }

                  else

                  {

                          curr_poly->vlist                                             = obj->vlist_trans;

                  }

                  if ( ! Insert_POLYF4DV1_RENDERLIST4DV1( rend_list, curr_poly))

                  {

                          curr_poly->vlist                                             = vlist_old;

                          return ( 0 );

 

                  }

                  curr_poly->vlist                                                     = vlist_old;

                 

         }

         return ( 1 );

 

}

当然,还要加上添加顶点到列表中,

int ddraw_liushuixian::Insert_POLY4DV1_RENDERLIST4DV1(RENDERLIST4DV1_PTR rend_list, POLY4DV1_PTR poly, ddraw_math math)

{

         if( rend_list->num_polys >= RENDERLIST4DV1_MAX_POLYS )

                  return ( 0 );

 

         rend_list->poly_ptrs[rend_list->num_polys]                                   = &rend_list->poly_data[rend_list->num_polys];

        

         rend_list->poly_data[rend_list->num_polys].state                 = poly->state;

         rend_list->poly_data[rend_list->num_polys].attr                   = poly->attr;

         rend_list->poly_data[rend_list->num_polys].color                = poly->color;

 

         math.VECTOR4D_COPY( & rend_list->poly_data[rend_list->num_polys].tvlist[0], & poly->vlist[poly->vert[0]] );

         math.VECTOR4D_COPY( & rend_list->poly_data[rend_list->num_polys].tvlist[1], & poly->vlist[poly->vert[1]] );

         math.VECTOR4D_COPY( & rend_list->poly_data[rend_list->num_polys].tvlist[2], & poly->vlist[poly->vert[2]] );

 

         math.VECTOR4D_COPY( & rend_list->poly_data[rend_list->num_polys].vlist[0], & poly->vlist[poly->vert[0]] );

         math.VECTOR4D_COPY( & rend_list->poly_data[rend_list->num_polys].vlist[1], & poly->vlist[poly->vert[1]] );

         math.VECTOR4D_COPY( & rend_list->poly_data[rend_list->num_polys].vlist[2], & poly->vlist[poly->vert[2]] );

 

         if( rend_list->num_polys == 0 )

         {

                  rend_list->poly_data[0].next                                                  = NULL;

                  rend_list->poly_data[0].prev                                                  = NULL;

         }

         else

         {

                  rend_list->poly_data[rend_list->num_polys].next                 = NULL;

                  rend_list->poly_data[rend_list->num_polys].prev                 = & rend_list->poly_data[rend_list->num_polys-1];

                  rend_list->poly_data[rend_list->num_polys-1].next     = & rend_list->poly_data[rend_list->num_polys];

 

         }

         rend_list->num_polys++;

 

         return ( 1 );

}

 

 

经过一系列调整,OK了

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 一遇冷空气就打喷嚏流鼻涕怎么办 打喷嚏鼻塞流清鼻涕怎么办 哺乳期鼻子不通气有鼻涕怎么办 宝宝热伤风流清鼻涕怎么办 哺乳期感冒流鼻涕怎么办最有效 小孩睡觉太晚了怎么办 孩子晚上睡觉不安稳怎么办 月子里宝宝睡觉不安稳怎么办 月子宝宝睡觉不安稳怎么办 孩子老是流黄鼻涕怎么办 孕妇流黄鼻涕怎么办速效办法 孕妇感冒流黄鼻涕怎么办 孕妇有黄痰和黄鼻涕怎么办 孕妇感冒了流黄鼻涕怎么办 怀孕感冒了怎么办鼻塞流鼻涕 怀孕初期感冒了怎么办鼻塞流鼻涕 怀孕9个月流鼻涕怎么办 怀孕5个月流鼻涕怎么办 小孩老是流黄鼻涕口臭怎么办 狗狗有食欲流黄鼻涕拉稀怎么办 小孩流黄鼻涕咳嗽怎么办 小狗感冒了一直打喷嚏怎么办 眼干眼屎多模糊怎么办 宝宝眼睛上火眼屎多怎么办 眼睛发干眼屎多怎么办 三个月宝宝眼睛流泪有眼屎怎么办 小孩眼睛流泪有眼屎怎么办 宝宝上火眼睛有好多眼屎怎么办 宝宝眼睛流泪还有眼屎怎么办? 新生儿眼睛上火眼屎多怎么办 铁耳屎在最里面怎么办 婴儿鼻屎特别深怎么办 鼻子干呼吸就疼怎么办 儿童鼻子里总有好多鼻屎怎么办 小孩鼻子里有鼻屎呼吸不通怎么办 鼻子不通通气鼻屎粘在鼻子怎么办 鼻子里面干燥长鼻屎怎么办 鼻孔里干的难受怎么办 每天有很多鼻屎怎么办 鼻子里面干的疼怎么办 婴儿鼻屎堵住了怎么办