2014年1月14日(DEMO7-2,加载PLG)

2014年1月14日星期二(DEMO7-2,加载3D线框立方体物体模型)

上个DEMO,是渲染列表,这个DEMO,进行了加载PLG模型,仍然是一步步地进行。

PLG模型首行包含了物体名称、顶点数和多边形数3部分组成。

加载模型时可以每次读取一行,并对其中的数字进行分析。

 

现在开始进行代码。

先设置摄像机坐标和位置,朝向,放缩比例,这里用的是物体,不是渲染列表。

 

// initialize camera position and direction

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

VECTOR4D cam_dir = {0,0,0,1};

 

// all your initialization code goes here...

VECTOR4D vscale={5.0,5.0,5.0,1},

         vpos = {0,0,0,1},

         vrot = {0,0,0,1};

OBJECT4DV1        obj;

 

 

读取一行数据换行的辅助函数

 

Char *  ddraw_liushuixian::Get_Line_PLG(char * buffer,int maxlength,FILE * fp )

{

    //跳过PLG文件中的注释和空行,返回一整行数据,如果文件为空,返回NULL

    int               index                 = 0;     //索引

    int               length                = 0;     //长度

 

    //进入分析循环

    while ( 1 )

    {

         //读取下一行

         if ( ! fgets(buffer, maxlength, fp ))

         {

             return NULL;

         }

         //计算空格数

         for ( length = strlen(buffer),index = 0; isspace(buffer[index]);index ++ );

        

         //检查是否是空行或注释

         if ( index >= length || buffer[index] == '#')

         {

             continue;;

         }

         //此时得到一个数据行

         return ( &buffer[index]);

    }

 

}

定义一些物体状态

 

#define OBJECT4DV1_STATE_ACTIVE                 0x0001

#define OBJECT4DV1_STATE_VISIBLE                0x0002

#define OBJECT4DV1_STATE_CULLED                 0x0004

 

加上一个函数计算平均半径和最大半径

 

 

void ddraw_liushuixian::Compute_OBJECT3DV1_RADIUS(OBJECT4DV1_PTR obj )

{

    obj->avg_radius                             = 0;

    obj->max_radius                             = 0;

 

    for ( int vertex = 0; vertex < obj->num_vertices;vertex++ )

    {

         float        dist_to_vertex            = sqrt( obj->vlist_local[vertex].x *obj->vlist_local[vertex].x +

                                                         obj->vlist_local[vertex].y *obj->vlist_local[vertex].y +

                                                         obj->vlist_local[vertex].z *obj->vlist_local[vertex].z );

         obj->avg_radius                        +=dist_to_vertex;

         if ( dist_to_vertex > obj->max_radius )

         {

             obj->max_radius                    =dist_to_vertex;

         }

        

    }

    obj->avg_radius                             /=obj->num_vertices;

 

}

就是一般的算法。

 

单双面标志

#define  PLX_1SIDED_FLAG                        0

#define PLX_2SIDED_FLAG                         1

 

//顶点属性

#define POLY4DV1_ATTR_2SIDED                0x0001

#define POLY4DV1_ATTR_TRANSPARENT           0x0002

#define POLY4DV1_ATTR_8BITCOLOR                 0x0004

#define POLY4DV1_ATTR_RGB16                     0x0008

#define POLY4DV1_ATTR_RGB24                     0x0010

//颜色模式

 

#define  PLX_COLOR_MODE_RGB_FLAG                0x8000

#define PLX_COLOR_MODE_INDEXED_FLAG             0x0000

 

 

//各种掩码

#define  PLX_RGB_MASK                       0x8000

#define  PLX_SHADE_MODE_MASK                    0x6000

#define PLX_2SIDED_MASK                         0x1000

#define PLX_COLOR_MASK                          0x0fff

 

//模型着色模式

#define PLX_SHADE_MODE_PURE_FLAG            0x0000

#define PLX_SHADE_MODE_CONSTANT_FLAG        0x0000

#define PLX_SHADE_MODE_FLAT_FLAG            0x2000

#define PLX_SHADE_MODE_GOURAUD_FLAG             0x4000

#define PLX_SHADE_MODE_PHONG_FLAG           0x6000

#define PLX_SHADE_MODE_FASTPHONG_FLAG       0x6000

与之对应的,是顶点着色模式

 

#define POLY4DV1_ATTR_SHADE_MODE_PURE       0x0020

#define POLY4DV1_ATTR_SHADE_MODE_CONSTANT   0x0020

#define POLY4DV1_ATTR_SHADE_MODE_FLAT       0x0040

#define POLY4DV1_ATTR_SHADE_MODE_GOURAUD    0x0080

#define POLY4DV1_ATTR_SHADE_MODE_PHONG      0x0100

#define POLY4DV1_ATTR_SHADE_MODE_FASTPHONG  0x0100

#define POLY4DV1_ATTR_SHADE_MODE_TEXTURE    0x0200

 

下面开始加载PLG模型

 

int ddraw_liushuixian::Load_OBJECT4DV1_PLG( OBJECT4DV1_PTR obj,char * filename, VECTOR4D_PTR scale, VECTOR4D_PTR pos, VECTOR4D_PTR rot )

{

         FILE         *                fp;                                               //?t??

         char                    buffer[256];                       //o??

         char  *                token_string;                      //?¨°°a¤??Ì??¬?ºyY?À?Ì???

 

         //¨¨¨°Ì??¬?¨¨º?¤?

 

         //̨²°????¨ª?º?¡¥OBJ

         memset( obj, 0, sizeof(OBJECT4DV1) );

         //??¬?Á¡ä¬?¦¨¨?a¨¦?¨ª?¡¥Ì?

         obj->state                                                                        = OBJECT4DV1_STATE_ACTIVE | OBJECT4DV1_STATE_VISIBLE;

 

         //¦¨¨??¬?Ì???

         obj->world_pos.x                                                           = pos->x;

         obj->world_pos.y                                                           = pos->y;

         obj->world_pos.z                                                           = pos->z;

         obj->world_pos.w                                                          = pos->w;

 

         //̨²2?ê?¨¢¨??t

         fp                                                                                             = fopen( filename,"r" );

         //̨²3?ê?¨¢¨??¬?¨¨º?¤?

         token_string                                                                    = Get_Line_PLG(buffer, 255, fp );

         //¤???¬?¨¨º?¤?

         sscanf(token_string, "%s %d %d", obj->name, & obj->num_vertices, & obj->num_polys );

 

         //̨²4?êo¨®?£¤Ì?¢DÀ¨ª

         for ( int vertex = 0; vertex < obj->num_vertices; vertex++ )

         {

                  token_string                                                           = Get_Line_PLG( buffer, 255, fp );

                  //¤??£¤Ì?

                  sscanf( token_string, "%f %f %f", & obj->vlist_local[vertex].x, & obj->vlist_local[vertex].y, & obj->vlist_local[vertex].z );

                  obj->vlist_local[vertex].w                             = 1;

 

                  //?¤?£¤Ì?Á?À¨º

                  obj->vlist_local[vertex].x                              *= scale->x;

                  obj->vlist_local[vertex].y                              *= scale->y;

                  obj->vlist_local[vertex].z                              *= scale->z;

         }

         //???¨´ã??¨ªÁ?䨮ã??

         Compute_OBJECT3DV1_RADIUS(obj);

 

         int                                        poly_surface_desc              = 0;                   //PLG/PLX¨¤À??¨¨º?¤?

         int                                        poly_num_verts                  = 0;                   //Ì¡À¡ã¨¤À??Ì?£¤Ì?ºy(a¤?¦¨¨¡§a3ê?

         char                            tmp_string[8];                                                       //ä?ä¡é¨¤À??¨¨º?¤?Ì?Á?¤?ä?

        

         //̨²5?êo¨®?¨¤À??¢DÀ¨ª

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

         {

                  token_string                                                           = Get_Line_PLG( buffer, 255,fp );

        

         //¨´¡§¨´®D¡ê¨ª?º?®¨¦¨y??Á¨¦¨¦ê?¨°??¨¤À???®D3?£¤Ì?ê???¨¨º?¤?¡é£¤Ì?ºy¨ª£¤Ì?¢DÀ¨ªä?ä¡éÌ?À?¢?D

         sscanf( token_string, "%s %s %d %d %d", tmp_string, & poly_num_verts, & obj->plist[poly].vert[0],

                  & obj->plist[poly].vert[1], & obj->plist[poly].vert[2]);

 

         //?®¨²0xaª¡¤Ì?16???D¨¬a

         if ( tmp_string[0] == '0' && toupper( tmp_string[1]) == 'X' )

         {

                  sscanf( tmp_string, "%x", & poly_surface_desc );

 

         }

         else

                  poly_surface_desc                                                 = atoi( tmp_string );

 

         //¨?¨¤À??£¤Ì?¢DÀ¨ª?¨°?¬?Ì?£¤Ì?¢DÀ¨ª

         obj->plist[poly].vlist                                              = obj->vlist_local;

 

         //ä?ä¡é£¤Ì?¢DÀ¨ª¨ª¨¤À??£¤Ì?¡Â°y¦Ì¨®ê?¤??¨¤À??¨¨º?¤?ê?¡éYä?¨¤®|Ì?¦¨¨?¨¤À??

         //¬¨¢¨?¨¤À??¨¨º?¤?DÌ????Á??

         if( poly_surface_desc & PLX_2SIDED_FLAG )

         {

                  SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_2SIDED );

         }

         //¦¨¨??¦?¡êº?

         //¨??º?16?

         if ( poly_surface_desc & PLX_COLOR_MODE_RGB_FLAG)

         {

                  SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_RGB16 );

                  //¬¨¢¨?RGB¦Ì

                  int                               red                                               = ( ( poly_surface_desc & 0x0f00) >> 8 );

                  int                               greeen                                          = ( ( poly_surface_desc & 0x00f0) >> 4 );

                  int                               blue                                     = ( poly_surface_desc & 0x000f );

 

                  obj->plist[poly].color                                    = _RGB16BIT565( red * 16, greeen * 16, blue * 16 );

         }

         else

         {

                  //使º1®?8??¦?¡Â°y

                  SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_8BITCOLOR );

                  //¬¨¢¨?Á?¨®Ì?8?¡ä¨¦Ì?Ì??¦?¡Â°y

                  obj->plist[poly].color                                    = ( poly_surface_desc & 0x00ff );

         }

 

         //ä|¤¨ªÁ?¦?¡êº?

         int                                        shade_mode                                = ( poly_surface_desc & PLX_SHADE_MODE_MASK );

 

         //¦¨¨?¨¤À??Ì?Á?¦?¡êº?

         switch ( shade_mode )

         {

         case PLX_SHADE_MODE_PURE_FLAG:

                  {

 

                          SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_SHADE_MODE_PURE );

 

 

                  }

                  break;

 

         case PLX_SHADE_MODE_FLAT_FLAG:

                  {

                          SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_SHADE_MODE_FLAT );

                  }

                  break;

 

         case PLX_SHADE_MODE_GOURAUD_FLAG:

                  {

 

                          SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_SHADE_MODE_GOURAUD );

                  }

                  break;

 

         case PLX_SHADE_MODE_PHONG_FLAG:

                  {

                          SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_SHADE_MODE_PHONG );

                  }

                  break;

         default:

                  break;

 

         }

         //Á?¨®?¨¤À??¦¨¨?a?¡¥Á¡ä¬?

         obj->plist[poly].state                                              = POLY4DV1_STATE_ACTIVE;

}

         //?À??t

         fclose( fp );

 

         return ( 1 );

 

 

 

 

}

 2014年1月20日星期一(继续DEMO7_2)

继续进行,设置摄像机。摄像机不变,在Game_Init()中加载模型

 

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

//设置模型在世界坐标系的位置

obj.world_pos.x                                                                      = 0;

obj.world_pos.y                                                                      = 0;

obj.world_pos.z                                                              = 100;

 

 

下一步就是在Game_main()中帧循环了

先重置模型,这里只是与背面消除有关,

背面消除在世界空间进行,只是看观察方向(物体->摄像机)与物体面法线夹角,小于90度则看到,大于90度则看不到,则可以消除,或者根据两向量的点乘,>0则看到,<0则看不到

void ddraw_liushuixian::Reset_OBJECT4DV1( OBJECT4DV1_PTR obj )

{

         RESET_BIT( obj->state, OBJECT4DV1_STATE_CULLED);

                          

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

         {

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

                  if ( ! curr_poly->state & POLY4DV1_STATE_ACTIVE)

                  {

                          continue;

                  }

                  RESET_BIT( curr_poly->state, POLY4DV1_STATE_CLIPPED );

                  RESET_BIT( curr_poly->state, POLY4DV1_STATE_BACKFACE );

 

         }

 

        

}

下一步对物体进行放缩和旋转,和渲染列表类似。只是对物体的局部顶点进行放缩和变换,并设置了是否考虑朝向,其实就是局部坐标轴的变换

 

void ddraw_liushuixian::Transform_OBJECT4DV1(OBJECT4DV1_PTR obj,

         MATRIX4X4_PTR mt,                       //变换矩阵

         int coord_select,

         int transform_basis,

         ddraw_math math2 )                   //指定要变换的坐标

{

         switch(  coord_select )

         {

         case TRANSFORM_LOCAL_ONLY:

                  {

                          //??¬?Ì?????/¡ê¨ª£¤Ì?Á?À¨º?DÀ??

                          for( int vertex = 0; vertex < obj->num_vertices; vertex++ )

                          {

                                  

                                            POINT4D                  presult;              //®?®¨²Yº¡Àä?ä¡éÀ??¨¢?

                                            math2.Mat_Mul_VECTOR4D_4X4( & obj->vlist_local[vertex], mt, & presult );

                                            math2.VECTOR4D_COPY( & obj->vlist_local[vertex], & presult );

                                  

                          }

                  }

                  break;

 

         case TRANSFORM_TRANS_ONLY:

                  {

 

                                   for(int vertex = 0; vertex < obj->num_vertices; vertex ++ )

                                   {

                                            //使º1®??¨®mt?£¤Ì??DÀ??

                                            POINT4D                  presult;              //®?®¨²Yº¡Àä?ä¡éÀ??¨¢?

                                            math2.Mat_Mul_VECTOR4D_4X4( & obj->vlist_trans[vertex], mt, & presult );

                                            math2.VECTOR4D_COPY( & obj->vlist_trans[vertex], & presult );

                                   }

                         

                  }

                  break;

 

         case TRANSFORM_LOCAL_TO_TRANS:

                  {

                          for( int vertex = 0; vertex < obj->num_vertices; vertex++ )

                          {

        

                                            //使º1®??¨®mt?£¤Ì??DÀ??

                                            math2.Mat_Mul_VECTOR4D_4X4( & obj->vlist_local[vertex], mt, & obj->vlist_trans[vertex] );

                                  

                          }

                  }

                  break;

 

         default:

                  break;

         }

 

         //Á?¨®¨¬¨¦º?¤??¡¥¨°¨°¢??DÀ??

         if ( transform_basis)

         {

                  //yÁa?¬?Ì?¡¥¨°¨°¢?

                  VECTOR4D                       vresult;                               //®?®¨²ä?ä¡éyÁa¨¢?

                  //yÁaux

                  math2.Mat_Mul_VECTOR4D_4X4( & obj->ux, mt, & vresult );

                  math2.VECTOR4D_COPY( & obj->ux, & vresult );

 

                  //yÁauy

                  math2.Mat_Mul_VECTOR4D_4X4( & obj->uy, mt, & vresult );

                  math2.VECTOR4D_COPY( & obj->uy, & vresult );

                  //yÁa uz

                  math2.Mat_Mul_VECTOR4D_4X4( & obj->uz, mt, & vresult );

                  math2.VECTOR4D_COPY( & obj->uz, & vresult );

         }

}

 

在每帧中,进行有朝向

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

下一步进行模型从模型坐标系到世界坐标系的转换,(即平移),只是不用列表中的多个物体,只有一个而已。

 

void ddraw_liushuixian::Model_To_World_OBJECT4DV1( OBJECT4DV1_PTR obj,  ddraw_math math2,int coord_select )

{

         if( coord_select == TRANSFORM_LOCAL_TO_TRANS )

         {

                 

 

                          //满足条件对其进行变换

                          for( int vertex = 0; vertex < obj->num_vertices; vertex ++ )

                          {

                                   //平移顶点                                   math2.VECTOR4D_ADD( & obj->vlist_local[vertex], & obj->world_pos, & obj->vlist_trans[vertex] );

                          }

                 

         }

         else

         {

                 

                          for( int vertex = 0; vertex < obj->num_vertices; vertex ++ )

                          {

                                   //平移顶点

                                   math2.VECTOR4D_ADD( & obj->vlist_trans[vertex], & obj->world_pos, & obj->vlist_trans[vertex] );

                          }

                  }

每帧改为

liushuixian.Model_To_World_OBJECT4DV1( & obj,* math );

相机变换矩阵一样

下面看下世界坐标到相机坐标的变换

 

 

void ddraw_liushuixian::World_To_Camera_OBJECT4DV1( ddraw_math math2, OBJECT4DV1_PTR obj, CAM4DV1_PTR cam )

{

         for( int vertex = 0; vertex < obj->num_vertices; vertex ++ )

         {

                  //使用相机对象中的矩阵mcma对顶点进行变换

                  POINT4D                  presult;              //用于存储每次变换的结果

                  //对顶点进行变换

                  math2.Mat_Mul_VECTOR4D_4X4( &obj->vlist_trans[vertex], &cam->mcam, &presult );

                  //将结果存回去

                  math2.VECTOR4D_COPY( & obj->vlist_trans[vertex], &presult );

         }

}

 

下面进行摄像机到透视坐标转换

 

void ddraw_liushuixian::Camera_To_Perspective_OBJECT4DV1( OBJECT4DV1_PTR obj, CAM4DV1_PTR cam )

{

         for( int vertex = 0; vertex < obj->num_vertices; vertex ++ )

         {

                  float                   z                                                   = obj->vlist_trans[vertex].z;

 

                  //根据相机的观察参数对顶点进行变换

                  obj->vlist_trans[vertex].x                              = cam->view_dist * obj->vlist_trans[vertex].x / z;

                  obj->vlist_trans[vertex].y                              = cam->view_dist * obj->vlist_trans[vertex].y * cam->aspect_ratio / z;

         }      

        

}

下面进行透视坐标到屏幕坐标的转换

 

void ddraw_liushuixian::Perspective_To_Screen_OBJECT4DV1( OBJECT4DV1_PTR obj, CAM4DV1_PTR cam )

{

    float              alpha                  = ( 0.5 * cam->viewport_width - 0.5 );

    float              beta                   = ( 0.5 * cam->viewport_height - 0.5 );

    //满足条件,对其进行变换

    for( int vertex = 0; vertex < obj->num_vertices; vertex ++ )

    {

        //顶点的透视坐标是归一化的,取值范围为-1到1,对坐标进行缩放,并反转Y轴

        obj->vlist_trans[vertex].x             = alpha + alpha * obj->vlist_trans[vertex].x;

        obj->vlist_trans[vertex].y             = beta - beta * obj->vlist_trans[vertex].y;

 

    }

 

 

}

 

现在看每一帧

liushuixian.Perspective_To_Screen_OBJECT4DV1( &obj, & cam );

最后需要绘制,线框模式+着色,基本类似,每个三角形面三个顶点,连线加色。代码如下所示

void ddraw_liushuixian::Draw_OBJECT4DV1_Wire16( ddraw_math math2, OBJECT4DV1_PTR obj, UCHAR * video_buffer,int lpitch )

{

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

         {

                 

 

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

                  if( !( obj->plist[poly].state & POLY4DV1_STATE_ACTIVE ) ||

                          ( obj->plist[poly].state & POLY4DV1_STATE_CLIPPED ) ||

                          (  obj->plist[poly].state & POLY4DV1_STATE_BACKFACE ) )

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

 

                  int                                        vindex_0                             = obj->plist[poly].vert[0];

                  int                                        vindex_1                             = obj->plist[poly].vert[1];

                  int                                        vindex_2                             = obj->plist[poly].vert[2];

 

                  //绘制三角形的边

                  //2d初始化过程中已经设置好裁剪,位于2D屏幕/窗口外的多边形都将被裁剪掉

                  math2.Draw_Clip_Line16(

                          obj->vlist_trans[vindex_0].x,

                          obj->vlist_trans[vindex_0].y,

                          obj->vlist_trans[vindex_1].x,

                          obj->vlist_trans[vindex_1].y,

                          obj->plist[poly].color,

                          video_buffer, lpitch );

 

                  math2.Draw_Clip_Line16(

                          obj->vlist_trans[vindex_1].x,

                          obj->vlist_trans[vindex_1].y,

                          obj->vlist_trans[vindex_2].x,

                          obj->vlist_trans[vindex_2].y,

                          obj->plist[poly].color,

                          video_buffer, lpitch );

 

                  math2.Draw_Clip_Line16(

                          obj->vlist_trans[vindex_2].x,

                          obj->vlist_trans[vindex_2].y,

                          obj->vlist_trans[vindex_0].x,

                          obj->vlist_trans[vindex_0].y,

                          obj->plist[poly].color,

                          video_buffer, lpitch );

         }

}

 

 

在每帧中绘制

         liushuixian.Draw_OBJECT4DV1_Wire16( *math, & obj, ddraw->getbackbuffer(), ddraw->getbacklpitch() );

OK,试试看吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值