2014年1月3日星期五(DEMO7_1终结)

下面将渲染列表从世界坐标系>摄像机坐标系

 

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

{

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

    {

         //获得当前多边形

         POLYF4DV1_PTR         curr_poly                 = rend_list->poly_ptrs[poly];

 

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

         if( ( curr_poly == NULL ) ||

             !( curr_poly->state & POLY4DV1_STATE_ACTIVE ) ||

             ( curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||

             ( curr_poly->state & POLY4DV1_STATE_BACKFACE ) )

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

 

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

         for( int vertex = 0; vertex < 3; vertex ++ )

         {

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

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

             //对顶点进行变换

             math.Mat_Mul_VECTOR4D_4X4( &curr_poly->tvlist[vertex], &cam->mcam, &presult );

             //将结果存回去

             math.VECTOR4D_COPY( & curr_poly->tvlist[vertex], &presult );

         }

    }

}

在每帧中调用

    liushuixian.World_To_Camera_RENDERLIST4DV1( math, &rend_list, &cam );

 

2014年1月6日星期一(流水线:相机坐标系到投影坐标系变换)

本来,不想多写,只想罗列写代码,不过,发现,我并没有真正搞明白透视这块,有必要加深印象。

视平面和视点之间的距离被称为视距(d)。

从物体的每点与视点发出一条连线,该线与视平面的交点就是投影。然后,在视平面上形成的图像被渲染到计算机屏幕上。

计算时,根据相似三角形,设要投影的点为P(x0,y0,z0),视点为(0,0,0),视距为d,则投影坐标为(x0*d/z0,y0*d/z0,d),当d=0时,无穷大,不能对z=0的顶点进行投影;z为负值时,物体被倒转投影。可以通过指定近裁剪面避免这两种情况。

通过矩阵变换的话,投影矩阵为

 

T = [1 0 0 0

     0 1 0 0

    0 0 1 1/d

    0 0 0 0]

则P点为

[x0 y0 z0 1] *  [1 0 0 0

                0 1 0 0

                0 0 1 1/d

                0 0 0 0]

 

=[x0 y0 z0 z0/d]

其中w=z0/d

将分量x,y,z都除以w,则坐标为

    [ x0*d/z0 y0*d/z0 d 1]

 

对于d的取值,可以任意。最合适的d值。

有两种选择,

可以选为1,这时候投影坐标变为

[x0/z0 y0/z0 1 1]

投影矩阵变为

T = [1 0 0 0

     0 1 0 0

    0 0 1 1

    0 0 0 0]

在fov为90的时候,坐标x和y都在-1和1之间,在转换到屏幕坐标时,要根据屏幕分辨率宽度*高度进行缩放,使之一致。在书上,宽高比就是x/y,也就是说,变宽的同时,必须变高,才能达到不变形。

另外一种设置d的方法是,根据屏幕坐标范围计算 ,考虑宽高比ar,则投影变换矩阵为

T = [d 0          0 0

     0 d*ar 0 0

    0 0      1 1

    0 0      0 0]

Xper              = x*d/z

Yper              = y *ar*d/z

 

透视投影将视景体内用相机坐标表示的点变换到视平面上,以便下一步将其变换为屏幕坐标,并可以将棱锥体视景体变成长方体。,以利于裁剪。

裁剪有两种方式,

1, 图像空间裁剪,就是先转换为屏幕坐标后,再用屏幕空间或视口裁剪,但是物体可能会在z<0处,需要在2D空间内对每个物体进行裁剪,像素测试

2, 在物体空间裁剪,在投影变换之前,消除物体 和/或背面,对所有不完全位于视景体的几何体进行裁剪。但是不但要裁剪多边形顶点,还需要裁剪纹理坐标和光照坐标。

投影变换可以将棱锥体变为立方体:将每个点乘以d再除以z坐标即可。

理论终于看完了,看下代码吧。

 

void ddraw_liushuixian::Camera_To_Perspective_RENDERLIST4DV1(RENDERLIST4DV1_PTR rend_list, CAM4DV1_PTR cam)

{

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

    {

         //获得当前多边形

         POLYF4DV1_PTR         curr_poly                 = rend_list->poly_ptrs[poly];

 

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

         if( ( curr_poly == NULL ) ||

             !( curr_poly->state & POLY4DV1_STATE_ACTIVE ) ||

             ( curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||

             ( curr_poly->state & POLY4DV1_STATE_BACKFACE ) )

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

 

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

         for( int vertex = 0; vertex < 3; vertex ++ )

         {

             float             z                         = curr_poly->tvlist[vertex].z;

            

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

             curr_poly->tvlist[vertex].x                 = cam->view_dist * curr_poly->tvlist[vertex].x / z;

             curr_poly->tvlist[vertex].y                 = cam->view_dist * curr_poly->tvlist[vertex].y * cam->aspect_ratio / z;

         }

    }

 

}

 

在game_main()每帧中,

    liushuixian.Camera_To_Perspective_RENDERLIST4DV1( &rend_list, & cam );

2014年1月7日星期二(流水线:转换到屏幕坐标)

这里我觉得很简单了,主要是坐标平移(必要时缩放)的问题,并反转Y轴,

 

void ddraw_liushuixian::Perspective_To_Screen_RENDERLIST4DV1(RENDERLIST4DV1_PTR rend_list, CAM4DV1_PTR cam)

{

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

    {

         //获得当前多边形

         POLYF4DV1_PTR         curr_poly                 = rend_list->poly_ptrs[poly];

 

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

         if( ( curr_poly == NULL ) ||

             !( curr_poly->state & POLY4DV1_STATE_ACTIVE ) ||

             ( curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||

             ( curr_poly->state & POLY4DV1_STATE_BACKFACE ) )

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

 

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

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

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

         for( int vertex = 0; vertex < 3; vertex ++ )

         {

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

             curr_poly->tvlist[vertex].x                 = alpha + alpha * curr_poly->tvlist[vertex].x;

             curr_poly->tvlist[vertex].y                 = beta - beta * curr_poly->tvlist[vertex].y;

         }

    }

}

在每帧中,调用

    liushuixian.Perspective_To_Screen_RENDERLIST4DV1( &rend_list, & cam );

流水线到这里应该结束了。

继续DEMO7-1,下面进行执行渲染列表,用线框模式和16位RGB颜色模式绘制渲染列表中所有的面,线框模式无需对多边形进行排序。

 

void ddraw_liushuixian::Draw_RENDERLIST4DV1_Wire16(ddraw_math math, RENDERLIST4DV1_PTR rend_list, UCHAR *video_buffer,int lpitch)

{

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

    {

         //获得当前多边形

         POLYF4DV1_PTR         curr_poly                 = rend_list->poly_ptrs[poly];

   

 

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

         if( ( curr_poly == NULL ) ||

             !( curr_poly->state & POLY4DV1_STATE_ACTIVE ) ||

             ( curr_poly->state & POLY4DV1_STATE_CLIPPED ) ||

             ( curr_poly->state & POLY4DV1_STATE_BACKFACE ) )

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

 

         //绘制三角形的边

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

         math.Draw_Clip_Line16(    rend_list->poly_ptrs[poly]->tvlist[0].x,

                                   rend_list->poly_ptrs[poly]->tvlist[0].y,

                                   rend_list->poly_ptrs[poly]->tvlist[1].x,

                                   rend_list->poly_ptrs[poly]->tvlist[1].y,

                                   rend_list->poly_ptrs[poly]->color,

                                   video_buffer, lpitch );

 

         math.Draw_Clip_Line16(    rend_list->poly_ptrs[poly]->tvlist[1].x,

                                   rend_list->poly_ptrs[poly]->tvlist[1].y,

                                   rend_list->poly_ptrs[poly]->tvlist[2].x,

                                   rend_list->poly_ptrs[poly]->tvlist[2].y,

                                   rend_list->poly_ptrs[poly]->color,

                                   video_buffer, lpitch );

 

         math.Draw_Clip_Line16(    rend_list->poly_ptrs[poly]->tvlist[2].x,

                                   rend_list->poly_ptrs[poly]->tvlist[2].y,

                                   rend_list->poly_ptrs[poly]->tvlist[0].x,

                                   rend_list->poly_ptrs[poly]->tvlist[0].y,

                                   rend_list->poly_ptrs[poly]->color,

                                   video_buffer, lpitch );

    }

 

 

}

 

 

 

在每一帧

    ddraw->DDraw_Lock_Back_Surface();

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

    ddraw->DDraw_Unlock_Back_Surface();

 

    ddraw->DDraw_Flip();

    mytool.Wait_Clock( 30 );

 

 

    结果发现没有三角形。只有黑屏。说明变换中某步或某几步有问题,

2014年1月8日星期三(诊断DEMO7-1)

    发现

    Insert_POLYF4DV1_RENDERLIST4DV1( & rend_list, &poly1 );

 

    Build_XYZ_Rotation_MATRIX4X4( 0, ang_y, 0, &mrot );

Build_CAM4DV1_Matrix_Euler( & cam, CAM_ROT_SEQ_ZYX );

 

 

Perspective_To_Screen_RENDERLIST4DV1( &rend_list, & cam );

    有问题,

 

 

从后往前看,发现

 

Perspective_To_Screen_RENDERLIST4DV1( &rend_list, & cam );

拼写错误。

改后,OK

2014年1月13日星期一(继续DEMO7-1)

继续往下纠正,

    liushuixian.Insert_POLYF4DV1_RENDERLIST4DV1( & rend_list, &poly1 );

    //Insert_POLYF4DV1_RENDERLIST4DV1( & rend_list, &poly1 );

 

有的话

也是笔误

    memcpy( ( void * ) & rend_list->poly_data[rend_list->num_polys], (void * )poly,sizeof( POLYF4DV1 ) );

,改掉后OK,继续往下走

 

Build_XYZ_Rotation_MATRIX4X4()这个函数也有问题,改造后不动了,

去掉各种SWITCH,只考虑绕Y轴旋转

实际上就是

 

MATRIX4X4 mx, my, mz,mtmp;      // working matrices

float sin_theta=0, cos_theta=0;   // used to initialize matrices

cos_theta = Fast_Cos(theta_y);

sin_theta = Fast_Sin(theta_y);

// set the matrix up

Mat_Init_4X4(&my,cos_theta, 0, -sin_theta, 0, 

              0,         1,  0,         0,

              sin_theta, 0, cos_theta,  0,

              0,         0, 0,          1);

// that's it, copy to output matrix

MAT_COPY_4X4(&my,mrot);

 

最后发现是cos_look[]和sin_look[]数组的缘故,有个fast_cos()和fast_sin()用到了,这里去掉这些,OK了,至此,流水线OK了,结果很简单,如下所示,

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值