2014年1月2日星期四(流水线-UVN系统的实现)

本文介绍了一种三维摄像机的初始化方法及基于欧拉角的摄像机变换矩阵的构建过程,包括摄像机属性设置、裁剪面计算、平移与旋转逆矩阵的计算等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        方位角A是绕+Y轴旋转的角度,与+Z轴重叠时为0度。

        仰角B是方向向量与地平面(X-Z平面)之间的夹角,假定为右手坐标系,则

r= psinB

y=pcosb

z=rcosA

x=-rsinA

 

初始化UVN相机,

先赋值给各个朝向

 

void ddraw_math::VECTOR4D_INITXYZ(VECTOR4D_PTR v, float x, float y, float z)

{

    v->x                               = x;

    v->y                               = y;

    v->z                               = z;

    v->w                               = 1.0;

}

 

零向量

 

void ddraw_math::VECTOR4D_ZERO(VECTOR4D_PTR v)

{

    v->x                               = 0;

    v->y                               = 0;

    v->z                               = 0;

    v->w                               = 1.0

}

加上初始化三维向量

 

void ddraw_math::VECTOR3D_INITXYZ(VECTOR3D_PTR v, float x, float y, float z)

{

    v->x                               = x;

    v->y                               = y;

    v->z                               = z;

}

 

 

初始化摄像机

void ddraw_liushuixian::Init_CAM4DV1(ddraw_math math, CAM4DV1_PTR cam, int cam_attr, POINT4D_PTR cam_pos, VECTOR4D_PTR cam_dir, POINT4D_PTR cam_target, float near_clip_z, float far_clip_z, float fov, float viewport_width, float viewport_height)

{

    cam->attr                          = cam_attr;       //相机属性

 

    math.VECTOR4D_COPY( & cam->pos, cam_pos );      //位置

    math.VECTOR4D_COPY( & cam->dir, cam_dir );      //欧拉相机的方向向量或角度

 

    //对于UVN相机

    math.VECTOR4D_INITXYZ( & cam->u, 1, 0, 0 );     //设置为+x轴方向

    math.VECTOR4D_INITXYZ( & cam->v, 0, 1, 0 );     //设置为+y轴方向

    math.VECTOR4D_INITXYZ( & cam->n, 0, 0, 1 );     //设置为+z轴方向

 

    if( cam_target != NULL )

         math.VECTOR4D_COPY( & cam->target, cam_target );     //UVN目标位置

    else

         math.VECTOR4D_ZERO( & cam->target );

 

    cam->near_clip_z               = near_clip_z;        //近裁剪面

    cam->far_clip_z                    = far_clip_z;         //远裁剪面

 

    cam->viewport_width                = viewport_width; //视口的大小

    cam->viewport_height           = viewport_height;

 

    cam->viewport_center_x             = ( viewport_width - 1 ) / 2;  //视口的中心

    cam->viewport_center_y             = ( viewport_height - 1 ) / 2;

 

    cam->aspect_ratio              = ( float ) viewport_width / ( float ) viewport_height;

 

    //将所有的矩阵都设置为单位矩阵

    math.Mat_IDENTITY_4X4( & cam->mcam );

    math.Mat_IDENTITY_4X4( & cam->mper );

    math.Mat_IDENTITY_4X4( & cam->mscr );

        

    cam->fov                       = fov;

    //将视平面大小设置为*(2/ar)

    cam->viewplane_width           = 2.0;

    cam->viewplane_height          = 2.0 / cam->aspect_ratio;

 

    //根据fov和视平面大小计算视距

    float        tan_fov_div2      = tan( DEG_TO_RAD( fov / 2 ) );

 

    cam->view_dist                     = 0.5 * cam->viewplane_width * tan_fov_div2;

 

    //判断fov是否为度

    if( fov == 90.0 )

    {

         //建立裁剪面

         POINT3D  pt_origin;        //裁剪面上的一个点

         math.VECTOR3D_INITXYZ( & pt_origin, 0, 0, 0 );

 

         VECTOR3D vn;      //面法线

         //右裁剪面

         math.VECTOR3D_INITXYZ( & vn, 1, 0, -1 );

         math.PLANE3D_Init( & cam->rt_clip_plane, & pt_origin, & vn, 1 );

 

         //左裁剪面

         math.VECTOR3D_INITXYZ( & vn, -1, 0, -1 );

         math.PLANE3D_Init( & cam->lt_clip_plane, & pt_origin, & vn, 1 );

 

         //上裁剪面

         math.VECTOR3D_INITXYZ( & vn, 0, 1, -1 );

         math.PLANE3D_Init( & cam->rt_clip_plane, & pt_origin, & vn, 1 );

 

 

         //下裁剪面

         math.VECTOR3D_INITXYZ( & vn, 0, -1, -1 );

         math.PLANE3D_Init( & cam->rt_clip_plane, & pt_origin, & vn, 1 );

    }

    else

    {

         //建立裁剪面

         POINT3D  pt_origin;        //裁剪面上的一个点

         math.VECTOR3D_INITXYZ( & pt_origin, 0, 0, 0 );

 

         VECTOR3D vn;      //面法线

         //右裁剪面

         math.VECTOR3D_INITXYZ( & vn, cam->view_dist, 0, -cam->viewplane_width / 2.0 );

         math.PLANE3D_Init( & cam->rt_clip_plane, & pt_origin, & vn, 1 );

 

        //左裁剪面

         math.VECTOR3D_INITXYZ( & vn, -cam->view_dist, 0, -cam->viewplane_width / 2.0 );

         math.PLANE3D_Init( & cam->lt_clip_plane, & pt_origin, & vn, 1 );

 

         //上裁剪面

         math.VECTOR3D_INITXYZ( & vn, 0, cam->view_dist, -cam->viewplane_width / 2.0 );

         math.PLANE3D_Init( & cam->rt_clip_plane, & pt_origin, & vn, 1 );

 

 

         //下裁剪面

         math.VECTOR3D_INITXYZ( & vn, 0, -cam->view_dist, -cam->viewplane_width / 2.0 );

         math.PLANE3D_Init( & cam->rt_clip_plane, & pt_origin, & vn, 1 );

    }

 

 

}

 

初始化几个变量

 

CAM4DV1                            cam;

定义两个摄像机类型

 

#define  CAM_MODEL_EULER                        0x0008

#define  CAM_MODEL_UVN                          0x0010

   

在Game_Init()中,初始化摄像机

    liushuixian.Init_CAM4DV1( math, & cam, CAM_MODEL_EULER, & cam_pos, & cam_dir, NULL, 50.0, 500.0, 90.0,SCREEN_WIDTH, SCREEN_HEIGHT );

 

在每帧中,建立摄像机变换矩阵

就是平移逆矩阵*三个旋转逆矩阵,旋转顺序根据用户定义

 

#define  CAM_ROT_SEQ_XYZ                        0

#define  CAM_ROT_SEQ_YXZ                        1

#define  CAM_ROT_SEQ_XZY                        2

#define  CAM_ROT_SEQ_YZX                        3

#define  CAM_ROT_SEQ_ZYX                        4

#define  CAM_ROT_SEQ_ZXY                        5

 

 

void ddraw_liushuixian::Build_CAM4DV1_Matrix_Euler( ddraw_math math,CAM4DV1_PTR cam, int cam_rot_seq)

{

    MATRIX4X4                 mt_inv,               //相机平移矩阵的逆矩阵

                               mx_inv,               //相机绕X轴的旋转矩阵的逆矩阵

                               my_inv,               //相机绕Y轴的旋转矩阵的逆矩阵

                               mz_inv,               //相机绕Z轴的旋转矩阵的逆矩阵

                               mrot,                 //所有逆旋转矩阵的鸡

                               mtmp;                 //用于存储临时矩阵

 

    //第步,根据相机位置计算相机平移矩阵的逆矩阵

    math.Mat_Init_4X4( & mt_inv, 1, 0, 0, 0,

                               0, 1, 0, 0,

                               0, 0, 1, 0,

                               -cam->pos.x, -cam->pos.y, -cam->pos.z, 1 );

 

    //第步,创建旋转矩阵的逆矩阵

    //要计算正规旋转矩阵,可以将其转置

    //也可以将每个旋转角度取负

    //首先计算个旋转矩阵取负

 

    //首先计算个旋转矩阵的逆矩阵

 

    float                     theta_x                   = cam->dir.x;

    float                     theta_y                   = cam->dir.y;

    float                     theta_z                   = cam->dir.z;

 

    //计算角度x的正弦和余弦

    float                     cos_theta                 = math.Fast_Cos( -theta_x );

    float                     sin_theta                 = math.Fast_Sin( -theta_x );

    //建立矩阵

    math.Mat_Init_4X4( & mx_inv,   1,       0,           0,           0,

                                       0,       cos_theta,   sin_theta,   0,

                                       0,       -sin_theta,  cos_theta,   0,

                                       0,       0,           0,           1 );

 

    //计算角度y的正弦和余弦

    cos_theta                                            = math.Fast_Cos( -theta_y );

    sin_theta                                            = math.Fast_Sin( -theta_y );

    //建立矩阵

    math.Mat_Init_4X4( & my_inv,   cos_theta,        0,           -sin_theta,           0,

                                       0,                1,           0,                    0,

                                       sin_theta,        0,           cos_theta,            0,

                                       0,                0,           0,                    1 );

 

    //计算角度z的正弦和余弦

    cos_theta                                            = math.Fast_Cos( -theta_z );

    sin_theta                                            = math.Fast_Sin( -theta_z );

    //建立矩阵

    math.Mat_Init_4X4( & mz_inv,   cos_theta,        sin_theta,   0,                    0,

                                       -sin_theta,       cos_theta,   0,                    0,

                                       0,                0,           1,                    0,

                                       0,                0,           0,                    1 );

 

    //现在计算逆旋转矩阵的乘积

    switch( cam_rot_seq )

    {

    case CAM_ROT_SEQ_XYZ:

         {

             math.Mat_Mul_4X4( & mx_inv, &my_inv, &mtmp );

             math.Mat_Mul_4X4( &mtmp, &mz_inv, &mrot );

         }

         break;

 

    case CAM_ROT_SEQ_YXZ:

         {

             math.Mat_Mul_4X4( &my_inv, &mx_inv, &mtmp );

             math.Mat_Mul_4X4( &mtmp, & mz_inv, &mrot );

         }

         break;

 

    case CAM_ROT_SEQ_XZY:

         {

             math.Mat_Mul_4X4( &mx_inv, &mz_inv, &mtmp );

             math.Mat_Mul_4X4( &mtmp, &my_inv, &mrot );

         }

         break;

 

    case CAM_ROT_SEQ_YZX:

         {

             math.Mat_Mul_4X4( &my_inv, &mz_inv, &mtmp );

             math.Mat_Mul_4X4( &mtmp, & mx_inv, &mrot );

         }

         break;

 

    case CAM_ROT_SEQ_ZYX:

         {

             math.Mat_Mul_4X4( &mz_inv, &my_inv, &mtmp );

             math.Mat_Mul_4X4( &mtmp, &mx_inv, &mrot );

         }

         break;

 

    case CAM_ROT_SEQ_ZXY:

         {

             math.Mat_Mul_4X4( &mz_inv, &mx_inv, &mtmp );

             math.Mat_Mul_4X4( &mtmp, &my_inv, &mrot );

         }

         break;

 

    default:

         break;

    }

    math.Mat_Mul_4X4( &mt_inv, &mrot, &cam->mcam );

   

 

}

在每帧创建相机变换坐标   

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值