• 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();
        }
    }
  • 相关阅读:
    mysql面试题
    Zookeeper与Kafka基础概念和原理
    Docker资源限制
    企业级仓库harbor搭建
    基于容器制作镜像
    docker基础学习(一)
    docker往阿里云推镜像和打包镜像
    Dockfile制作镜像
    算法Sedgewick第四版-第1章基础-006一封装输出(文件)
    算法Sedgewick第四版-第1章基础-005一封装输入(可以文件,jar包里的文件或网址)
  • 原文地址:https://www.cnblogs.com/zhihai/p/2437792.html
Copyright © 2020-2023  润新知