方位角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 );