Viewport3D中的摄像机(二、摄像机动作)

前文介绍了Viewport3D中的两种摄像机:OrthographicCamera和PerspectiveCamera。在3D场景里漫游,最主要的工作就是针对用户输入(例如鼠标左右移动、键盘按下A、W、S、D等键)来改变摄像机的位置、方向。本文接下来介绍如何通过改变PerspectiveCamera的属性,来达到场景的漫游效果。

摄像机动作

我摄像机的动作可以分成三类、移动、旋转、拉升镜头。用一个枚举来描述这些动作:

public enum SceneCameraAction
{
    MoveForward,    //向前移动
    MoveBack,       //向后移动
    MoveLeft,       //向左移动
    MoveRight,      //向后移动
    MoveUp,         //向上移动
    MoveDown,       //向下移动
    TurnLeft,       //左转
    TurnRight,      //右转
    TurnUp,         //向上看
    TurnDown,       //向下看
    ZoomIn,         //拉近镜头
    ZoomOut,        //拉远镜头
}

移动摄像机

在WPF3D里,可以通过改变计算机的Position属性,来移动PerspectiveCamera,假设摄像机的移动速度为Speed,有以下移动公式:

新坐标=原坐标+速度×移动方向

 

下图为摄像机向前、向左、向上移动的方向,为了方便计算,移动方向都为单位向量。

image

向前、向后移动

向前移动的移动方向为LookDirection,向后为-1*LookDirection

向前移动:

Camera.Position += (Speed * Camera.LookDirection);

向后移动

Camera.Position -= (Speed * Camera.LookDirection);

向左、向右移动

向左、向右移动,相当于在XZ平面上,沿着摄像机的LookDirection投影垂直的直线方向移动。

向左移动:

Camera.Position += Speed * (Camera.LookDirection.Rotate(0, Math.PI / 2, 0).GetUnit());

 

向右移动:

Camera.Position += Speed * (Camera.LookDirection.Rotate(0, -1 * Math.PI / 2, 0).GetUnit());

上面的变换,我用了两个扩展函数:

把向量旋转拆分成分别绕x轴、y轴、z轴旋转:

image

用以下函数计算一个向量分别绕x、y、z轴旋转后得到的新向量:

/// <summary>
/// 向量旋转
/// </summary>
/// <param name="x">绕x轴旋转值</param>
/// <param name="y">绕y轴旋转值</param>
/// <param name="z">绕z轴旋转值</param>
/// <returns>旋转结果</returns>
public static Vector3D Rotate(this Vector3D vector3D,double x, double y, double z)
{
    Matrix3D rotateX = new Matrix3D(
        1,              0,              0,              0,
        0,              Math.Cos(x),    Math.Sin(x),    0,
        0,              -Math.Sin(x),   Math.Cos(x),    0,
        0,              0,              0,              1);

    Matrix3D rotateY = new Matrix3D(
        Math.Cos(y),    0,              -Math.Sin(y),   0,
        0,              1,              0,              0,
        Math.Sin(y),    0,              Math.Cos(y),    0,
        0,              0,              0,              1);

    Matrix3D rotateZ = new Matrix3D(
        Math.Cos(z),    Math.Sin(z),    0,              0,
        -Math.Sin(z),   Math.Cos(z),    0,              0,
        0,              0,              1,              0,
        0,              0,              0,              1);

    return vector3D * rotateX * rotateY * rotateZ;

}

 

GetUnit函数是计算一个响亮的单位向量:

public static Vector3D GetUnit(this Vector3D vector3D)
{
    double length = 1.0d;
    return new Vector3D(vector3D.X * length / vector3D.Length,
        vector3D.Y * length / vector3D.Length,
        vector3D.Z * length / vector3D.Length);
}

 

向上、向下移动

向上、向下移动相当于延y轴改变Camera的Position属性:

向上移动:

Camera.Position += Speed * new Vector3D(0, 1, 0);

 

向下移动:

Camera.Position += Speed * new Vector3D(0, -1, 0);

 

旋转摄像机

和移动摄像机不同,旋转摄像机时,保持摄像机的Position属性不变,根据旋转值修改摄像机的LookDirection属性。这里仅仅假设绕Y轴旋转:

/// <summary>
/// 旋转摄像头
/// </summary>
/// <param name="ModelCameraAction">旋转角度</param>
public void Turn(SceneCameraAction ModelCameraAction)
{
    double speed = Math.PI / 60;

    if (ModelCameraAction == SceneCameraAction.TurnLeft)
    {
        Camera.LookDirection = Camera.LookDirection.Rotate(0, speed, 0).GetUnit();
    }

    if (ModelCameraAction == SceneCameraAction.TurnRight)
    {
        Camera.LookDirection = Camera.LookDirection.Rotate(0, -1 * speed, 0).GetUnit();
    }
}
posted @ 2012-04-08 17:40  @张凯@  阅读(764)  评论(0编辑  收藏  举报