原帖地址:http://ogldev.atspace.co.uk/www/tutorial13/tutorial13.html
在前面的教程中,我们都是默认摄像机坐标在三维坐标的原点,本篇教程我们开始讨论把摄像机放在三维空间的任意位置,从而更方便的从不同视角观察物体。决定三维空间摄像机坐标系有三个因素,摄像机的在三维空间的位置,摄像机lookat的方向向量,摄像机的up方向向量,有了这三个值,我们就可以确定三维空间摄像机的位置和方位,从而推导出世界坐标系到摄像机坐标的转化矩阵。
具体推导见我转的另外一篇文章:http://www.cnblogs.com/mikewolf2002/archive/2012/11/25/2787636.html
主要代码变化:
建立一个矩阵类Matrix4f,用来管理所有的矩阵操作。
pipeline.h
struct {
Vector3f Pos;
Vector3f Target;
Vector3f Up;
} m_camera;
Vector3f Pos;
Vector3f Target;
Vector3f Up;
} m_camera;
math3d.h
Vector3f Vector3f::Cross(const Vector3f& v) const
{
const float _x = y * v.z - z * v.y;
const float _y = z * v.x - x * v.z;
const float _z = x * v.y - y * v.x;
return Vector3f(_x, _y, _z);
}
{
const float _x = y * v.z - z * v.y;
const float _y = z * v.x - x * v.z;
const float _z = x * v.y - y * v.x;
return Vector3f(_x, _y, _z);
}
向量类Vector3f增加了2个向量叉积的函数。
math3d.h
Vector3f& Vector3f::Normalize()
{
const float Length = sqrtf(x * x + y * y + z * z);
x /= Length;
y /= Length;
z /= Length;
return *this;
}
{
const float Length = sqrtf(x * x + y * y + z * z);
x /= Length;
y /= Length;
z /= Length;
return *this;
}
注意:右向量是根据叉积算出来的。
math3d.cpp
void Matrix4f::InitCameraTransform(const Vector3f& Target, const Vector3f& Up)
{
Vector3f N = Target;
N.Normalize();
Vector3f U = Up;
U.Normalize();
U = U.Cross(Target);
Vector3f V = N.Cross(U);
m[0][0] = U.x; m[0][1] = U.y; m[0][2] = U.z; m[0][3] = 0.0f;
m[1][0] = V.x; m[1][1] = V.y; m[1][2] = V.z; m[1][3] = 0.0f;
m[2][0] = N.x; m[2][1] = N.y; m[2][2] = N.z; m[2][3] = 0.0f;
m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f;
}
{
Vector3f N = Target;
N.Normalize();
Vector3f U = Up;
U.Normalize();
U = U.Cross(Target);
Vector3f V = N.Cross(U);
m[0][0] = U.x; m[0][1] = U.y; m[0][2] = U.z; m[0][3] = 0.0f;
m[1][0] = V.x; m[1][1] = V.y; m[1][2] = V.z; m[1][3] = 0.0f;
m[2][0] = N.x; m[2][1] = N.y; m[2][2] = N.z; m[2][3] = 0.0f;
m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f;
}
pipeline.cpp
const Matrix4f* Pipeline::GetTrans()
{
Matrix4f ScaleTrans, RotateTrans, TranslationTrans, CameraTranslationTrans, CameraRotateTrans, PersProjTrans;
ScaleTrans.InitScaleTransform(m_scale.x, m_scale.y, m_scale.z);
RotateTrans.InitRotateTransform(m_rotateInfo.x, m_rotateInfo.y, m_rotateInfo.z);
TranslationTrans.InitTranslationTransform(m_worldPos.x, m_worldPos.y, m_worldPos.z);
CameraTranslationTrans.InitTranslationTransform(-m_camera.Pos.x, -m_camera.Pos.y, -m_camera.Pos.z);
CameraRotateTrans.InitCameraTransform(m_camera.Target, m_camera.Up);
PersProjTrans.InitPersProjTransform(m_persProj.FOV, m_persProj.Width, m_persProj.Height, m_persProj.zNear, m_persProj.zFar);
m_transformation = PersProjTrans * CameraRotateTrans * CameraTranslationTrans * TranslationTrans * RotateTrans * ScaleTrans;
return &m_transformation;
}
{
Matrix4f ScaleTrans, RotateTrans, TranslationTrans, CameraTranslationTrans, CameraRotateTrans, PersProjTrans;
ScaleTrans.InitScaleTransform(m_scale.x, m_scale.y, m_scale.z);
RotateTrans.InitRotateTransform(m_rotateInfo.x, m_rotateInfo.y, m_rotateInfo.z);
TranslationTrans.InitTranslationTransform(m_worldPos.x, m_worldPos.y, m_worldPos.z);
CameraTranslationTrans.InitTranslationTransform(-m_camera.Pos.x, -m_camera.Pos.y, -m_camera.Pos.z);
CameraRotateTrans.InitCameraTransform(m_camera.Target, m_camera.Up);
PersProjTrans.InitPersProjTransform(m_persProj.FOV, m_persProj.Width, m_persProj.Height, m_persProj.zNear, m_persProj.zFar);
m_transformation = PersProjTrans * CameraRotateTrans * CameraTranslationTrans * TranslationTrans * RotateTrans * ScaleTrans;
return &m_transformation;
}
下面代码把摄像机从原点移动到(1.0,1.0,-3.0)的位置,摄像机对准位置(0.45f, 0.0f, 1.0f),摄像机的up方向是y轴正方向。
tutorial13.cpp
Vector3f CameraPos(1.0f, 1.0f, -3.0f);
Vector3f CameraTarget(0.45f, 0.0f, 1.0f);
Vector3f CameraUp(0.0f, 1.0f, 0.0f);
p.SetCamera(CameraPos, CameraTarget, CameraUp);
Vector3f CameraTarget(0.45f, 0.0f, 1.0f);
Vector3f CameraUp(0.0f, 1.0f, 0.0f);
p.SetCamera(CameraPos, CameraTarget, CameraUp);