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

本文介绍了一种PLG模型的加载和解析方法,包括模型文件的读取、顶点和多边形数据的处理,以及如何计算物体的平均半径和最大半径等关键步骤。

上个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;      //文件指针
 char   buffer[256];   //缓冲区
 char *  token_string;   //指向要分析的物体数据文本的指针

 //先找到物体描述符

 //第一步清空和初始化OBJ
 memset( obj, 0, sizeof(OBJECT4DV1) );
 //将物体状态设置为可见和活动的
 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步,读取文件
 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步:加载顶点列表
 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;   //当前多边形得顶点数(这里设定为3)
 char    tmp_string[8];       //存储多边形描述符的字符串
 
 //第5步:加载多边形列表
 for( int poly = 0; poly < obj->num_polys; poly++ )
 {
  token_string       = Get_Line_PLG( buffer, 255,fp );
 
 //假定所有模型都是由三角形组成,则每个多边形都有3个顶点,将面描述符、顶点数和顶点列表存储到变量中
 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]);

 //对于0x开头的16进制进行检测
 if ( tmp_string[0] == '0' && toupper( tmp_string[1]) == 'X' )
 {
  sscanf( tmp_string, "%x", & poly_surface_desc );

 }
 else
  poly_surface_desc      = atoi( tmp_string );

 //让多边形顶点列表指向物体的顶点列表
 obj->plist[poly].vlist      = obj->vlist_local;

 //存储顶点列表和多边形顶点索引值后,分析多边形描述符,并据此相应地设置多边形
 //提取多边形描述符中的每个位字段
 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
 {
  //使用8位颜色索引
  SET_BIT( obj->plist[poly].attr, POLY4DV1_ATTR_8BITCOLOR );
  //提取最后的8位即可得到颜色索引
  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;

 }
 //最后将多边形设置为活动状态
 obj->plist[poly].state      = POLY4DV1_STATE_ACTIVE;

 //关闭文件
 fclose( fp );

 return ( 1 );

 


}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值