本篇是
创建游戏内核(5)的续篇,其中涉及到矩阵以及坐标系统变换的知识请参阅
DirectX
9的一些数学计算函数:矩阵,坐标变换。以及
DirectX
9的坐标系统变换。
视口变换和CAMERA
CAMERA类和 WORLD_POSITION类非常类似,但CAMERA类处理的是视口变换矩阵。
来看看CAMERA类的定义:
//================================================================================
// Defines for class CAMERA.
//================================================================================
class CAMERA
{
protected:
float _x_pos, _y_pos, _z_pos; // camera current position
float _x_rot, _y_rot, _z_rot; // camera current rotation
float _start_x_pos, _start_y_pos, _start_z_pos; // start tracking position
float _start_x_rot, _start_y_rot, _start_z_rot; // start tracking rotation
float _end_x_pos, _end_y_pos, _end_z_pos; // end tracking position
float _end_x_rot, _end_y_rot, _end_z_rot; // end tracking rotation
D3DXMATRIX _mat_world; // world transform matrix
D3DXMATRIX _mat_translation; // translation matrix
D3DXMATRIX _mat_rotation; // rotation matrix
public:
CAMERA();
D3DXMATRIX* Get_Matrix();
void Update();
void Move(float x_pos, float y_pos, float z_pos);
void Move_Rel(float x_add, float y_add, float z_add);
void Rotate(float x_rot, float y_rot, float z_rot);
void Rotate_Rel(float x_add, float y_add, float z_add);
void Point(float x_eye, float y_eye, float z_eye, float x_at, float y_at, float z_at);
void Set_Start_Track();
void Set_End_Track();
void Track(float time_ratio, float time_length);
float Get_X_Pos();
float Get_Y_Pos();
float Get_Z_Pos();
float Get_X_Rotation();
float Get_Y_Rotation();
float Get_Z_Rotation();
};
接着是CAMERA类的实现:
//-------------------------------------------------------------------
// Constructor, initialize camera's current position and rotation.
//-------------------------------------------------------------------
CAMERA::CAMERA()
{
Move(0.0, 0.0, 0.0);
Rotate(0.0, 0.0, 0.0);
Update();
}
//-------------------------------------------------------------------
// Move camera to new position.
//-------------------------------------------------------------------
void CAMERA::Move(float x_pos, float y_pos, float z_pos)
{
_x_pos = x_pos; _y_pos = y_pos; _z_pos = z_pos;
D3DXMatrixTranslation(&_mat_translation, -x_pos, -y_pos, -z_pos);
}
//-------------------------------------------------------------------
// Move camera to new positoin which is summed by current position and
// added position.
//-------------------------------------------------------------------
void CAMERA::Move_Rel(float x_add, float y_add, float z_add)
{
Move(_x_pos + x_add, _y_pos + y_add, _z_pos + z_add);
}
//-------------------------------------------------------------------
// Build rotation matrix.
//-------------------------------------------------------------------
void CAMERA::Rotate(float x_rot, float y_rot, float z_rot)
{
D3DXMATRIX mat_x_rot, mat_y_rot, mat_z_rot;
_x_rot = x_rot; _y_rot = y_rot; _z_rot = z_rot;
D3DXMatrixRotationX(&mat_x_rot, -x_rot);
D3DXMatrixRotationX(&mat_y_rot, -y_rot);
D3DXMatrixRotationX(&mat_z_rot, -z_rot);
_mat_rotation = mat_z_rot;
D3DXMatrixMultiply(&_mat_rotation, &_mat_rotation, &mat_y_rot);
D3DXMatrixMultiply(&_mat_rotation, &_mat_rotation, &mat_x_rot);
}
//-------------------------------------------------------------------
// Build rotation matrix which is summed by current rotation value
// and added rotation value.
//-------------------------------------------------------------------
void CAMERA::Rotate_Rel(float x_add, float y_add, float z_add)
{
Rotate(_x_rot + x_add, _y_rot + y_add, _z_rot + z_add);
}
//-------------------------------------------------------------------
// Move camera to new position and look at new target position.
//-------------------------------------------------------------------
void CAMERA::Point(float x_eye, float y_eye, float z_eye, float x_at, float y_at, float z_at)
{
// Calculate angles between points
float x_diff = x_at - x_eye;
float y_diff = y_at - y_eye;
float z_diff = z_at - z_eye;
float x_rot = (float) atan2(-y_diff, sqrt(x_diff * x_diff + z_diff * z_diff));
float y_rot = (float) atan2(x_diff, z_diff);
// Move camera to new position and look at new target
Move(x_eye, y_eye, z_eye);
Rotate(x_rot, y_rot, 0.0);
}
//-------------------------------------------------------------------
// Set camera's start tracking position and rotation.
//-------------------------------------------------------------------
void CAMERA::Set_Start_Track()
{
_start_x_pos = _x_pos; _start_y_pos = _y_pos; _start_z_pos = _z_pos;
_start_x_rot = _x_rot; _start_y_rot = _y_rot; _start_z_rot = _z_rot;
}
//-------------------------------------------------------------------
// Set camera's end tracking position and rotation.
//-------------------------------------------------------------------
void CAMERA::Set_End_Track()
{
_end_x_pos = _x_pos; _end_y_pos = _y_pos; _end_z_pos = _z_pos;
_end_x_rot = _x_rot; _end_y_rot = _y_rot; _end_z_rot = _z_rot;
}
//-------------------------------------------------------------------
// Move camera to new position and ratation by giving time,
// 0 <= time_ratio <= 1.
//-------------------------------------------------------------------
void CAMERA::Track(float time_ratio, float time_length)
{
float time_offset = time_length * time_ratio;
float x = (_end_x_pos - _start_x_pos) / time_length * time_offset;
float y = (_end_y_pos - _start_y_pos) / time_length * time_offset;
float z = (_end_z_pos - _start_z_pos) / time_length * time_offset;
Move(_start_x_pos + x, _start_y_pos + y, _start_z_pos + z);
x = (_end_x_rot - _start_x_rot) / time_length * time_offset;
y = (_end_y_rot - _start_y_rot) / time_length * time_offset;
z = (_end_z_rot - _start_z_rot) / time_length * time_offset;
Rotate(_start_x_rot + x, _start_y_rot + y, _start_z_rot + z);
}
//-------------------------------------------------------------------
// Update new camera world transform matrix.
//-------------------------------------------------------------------
void CAMERA::Update()
{
D3DXMatrixMultiply(&_mat_world, &_mat_translation, &_mat_rotation);
}
//-------------------------------------------------------------------
// Get camera world transform matrix.
//-------------------------------------------------------------------
D3DXMATRIX* CAMERA::Get_Matrix()
{
Update();
return &_mat_world;
}
//-------------------------------------------------------------------
// Get camera current position (x coordinate).
//-------------------------------------------------------------------
float CAMERA::Get_X_Pos()
{
return _x_pos;
}
//-------------------------------------------------------------------
// Get camera current position (y coordinate).
//-------------------------------------------------------------------
float CAMERA::Get_Y_Pos()
{
return _y_pos;
}
//-------------------------------------------------------------------
// Get camera current position (z coordinate).
//-------------------------------------------------------------------
float CAMERA::Get_Z_Pos()
{
return _z_pos;
}
//-------------------------------------------------------------------
// Get camera current rotation (x coordinate).
//-------------------------------------------------------------------
float CAMERA::Get_X_Rotation()
{
return _x_rot;
}
//-------------------------------------------------------------------
// Get camera current rotation (y coordinate).
//-------------------------------------------------------------------
float CAMERA::Get_Y_Rotation()
{
return _y_rot;
}
//-------------------------------------------------------------------
// Get camera current rotation (z coordinate).
//-------------------------------------------------------------------
float CAMERA::Get_Z_Rotation()
{
return _z_rot;
}
CAMERA类和WORLD_POSITION类惟一的不同就是加上了Point、Set_Start_Track、
Set_End_Track以及Track函数。Point函数用来确定观察点的方位并在瞬间将它指向一个特定的方向。
三个同追踪有关的函数随着时间追踪摄像机的移动路径。要使用摄像机追踪方位,将摄像机放到预想的起始位置并调用CAMERA::
Set_Start_Track,然后再将摄像机移动到预想的结束方位并调用CAMERA::Set_End_Track即可。
接下来需要调用CAMERA::Track函数(要在调用CAMERA::Update之前调用它)沿着创建的轨迹来定位摄像机。
Track函数的time_ratio参数的范围从0.0(起始方位)-1.0(结束方位),任何介于此范围内的值都会将摄像机沿着轨迹进行移动,
time_length可以是任意起作用的值(举例来说,毫秒)。
摄像机追踪创建了一些很棒的效果,下面的示例说明了这一点:
CAMERA camera;
// 移到位置(0.0, 100.0, -100.0)处并朝向原点
camera.Point(0.0, 100.0, -100.0, 0.0, 0.0, 0.0);
camera.Set_Start_Track();
// 移到结束方位
camera.Point(-100.0, 0.0, 0.0, 0.0, 100.0, 0.0);
camera.Set_End_Track();
// 每过10000毫秒将摄像机放置到起始方位和结束方位的一半处
camera.Track(0.5, 10000);
camera.Update();