C#DirectX3D开发(2) c#写的DirectX3D的摄像机类

下面是完整的类:

using System;

using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
namespace D3DLib
{
    public enum CameraMode
    {
        Rotate,Move
    }

    public class Camera
    {
        private Device device;
        public Camera(Device d)
        {
            device = d;
            //lastXAixs = new Vector3(1, 0, 0);
        }

        /// <summary>
        /// 定义摄像机位置
        /// </summary>
        public Vector3 Postion = new Vector3(10, 10, -50);
        /// <summary>
        /// 定义摄像机目标位置
        /// </summary>
        public Vector3 Target = new Vector3(10, 10, 0);

        /// <summary>
        /// 向上方向
        /// </summary>
        public Vector3 UpVector = new Vector3(0, 1, 0);
        /// <summary>
        /// 向上方向
        /// </summary>
        public Vector3 YVector = new Vector3(0, 1, 0);
        /// <summary>
        /// 向上方向
        /// </summary>
        public Vector3 XVector = new Vector3(1, 0, 0);
        /// <summary>
        /// 向上方向
        /// </summary>
        public Vector3 ZVector = new Vector3(0, 0, 1);
        /// <summary>
        /// 定义绕Y轴旋转变量
        /// </summary>
        private const float angleSpeed = 0.05f;
        private float currentAngle = 0;
        /// <summary>
        /// 记录鼠标按下时的坐标位置
        /// </summary>
        private int _mouseLastX;
        /// <summary>
        /// 记录鼠标按下时的坐标位置
        /// </summary>
        private int _mouseLastY;
        /// <summary>
        /// 记录是否由鼠标控制旋转
        /// </summary>
        private bool _isRotate;
        /// <summary>
        /// 记录是否由鼠标控制移动
        /// </summary>
        private bool _isMove;
        private float _zNearPlane = 1f;
        private float _zFarPlane = 500f;
        /// <summary>
        /// 近平面距离,太大的话就看不清近处的东西了
        /// </summary>
        public float ZNearPlane
        {
            get { return _zNearPlane; }
            set { _zNearPlane = value; }
        }
        /// <summary>
        /// 远平面距离,太小的话看不清远处的东西,应该是在远平面外的东西就不渲染了吧
        /// </summary>
        public float ZFarPlane
        {
            get { return _zFarPlane; }
            set { _zFarPlane = value; }
        }
        /// <summary>
        /// 移动速度
        /// </summary>
        public float MoveSpeed = 0.1f;
        /// <summary>
        /// 当前摄像机的视图矩阵的X轴方向
        /// </summary>
        private Vector3 XAxis
        {
            get
            {
                Matrix currentView = device.Transform.View;
                Vector3 axis = new Vector3(currentView.M11, currentView.M21, currentView.M31);
                return axis;
            }
        }
        /// <summary>
        /// 当前摄像机的视图矩阵的Y轴方向
        /// </summary>
        private Vector3 YAxis
        {
            get
            {
                Matrix currentView = device.Transform.View;
                Vector3 axis = new Vector3(currentView.M12, currentView.M22, currentView.M32);
                return axis;
            }
        }
        private Vector3 ZAxis
        {
            get
            {
                Matrix currentView = device.Transform.View;
                Vector3 axis = new Vector3(currentView.M13, currentView.M23, currentView.M33);
                return axis;
            }
        }
        private int _lastWidth;
        private int _lastHeight;
        public void SetUpCamera()
        {
            SetUpCamera(_lastWidth, _lastHeight);
        }
        /// <summary>
        /// 设置摄像机
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public void SetUpCamera(int width,int height)
        {
            _lastWidth = width;
            _lastHeight = height;
            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, width / height, ZNearPlane, ZFarPlane);
            //device.Transform.View = Matrix.LookAtLH(Postion, Target, UpVector);
            SetDeviceView();
        }
        /// <summary>
        /// 开始旋转或者移动
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="mode"></param>
        public void StartChange(int x,int y,CameraMode mode)
        {
            _mouseLastX = x;
            _mouseLastY = y;
            if (mode == CameraMode.Rotate)
            {
                _isRotate = true;
            }
            else if (mode == CameraMode.Move)
            {
                _isMove = true;
            }
        }
        /// <summary>
        /// 结束旋转或者移动
        /// </summary>
        public void EndChange()
        {
            _isRotate = false;
            _isMove = false;
        }
        /// <summary>
        /// 旋转或者移动
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public void Change(int x, int y, int width, int height)
        {
            if (_isRotate)
            {
                Rotate(x, y, width, height);
            }
            else if (_isMove)
            {
                Move(x, y);
            }
        }
        /// <summary>
        /// 移动摄像头
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void Move(int x, int y)
        {
            Matrix currentView = device.Transform.View;//当前摄像机的视图矩阵
            
            Target.X += -MoveSpeed * ((x - _mouseLastX) * currentView.M11 - (y - _mouseLastY) * currentView.M12);
            Target.Y += -MoveSpeed * ((x - _mouseLastX) * currentView.M21 - (y - _mouseLastY) * currentView.M22);
            Target.Z += -MoveSpeed * ((x - _mouseLastX) * currentView.M31 - (y - _mouseLastY) * currentView.M32);


            Postion.X += -MoveSpeed * ((x - _mouseLastX) * currentView.M11 - (y - _mouseLastY) * currentView.M12);
            Postion.Y += -MoveSpeed * ((x - _mouseLastX) * currentView.M21 - (y - _mouseLastY) * currentView.M22);
            Postion.Z += -MoveSpeed * ((x - _mouseLastX) * currentView.M31 - (y - _mouseLastY) * currentView.M32);


            //device.Transform.View = Matrix.LookAtLH(Postion, Target, UpVector);
            SetDeviceView();
            _mouseLastX = x;
            _mouseLastY = y;
        }
        public void MoveLeft()
        {
            RotateYAxis(-angleSpeed);
        }
        public void MoveRight()
        {
            RotateYAxis(angleSpeed);
        }
        public void MoveUp()
        {
            RotateXAxis(-angleSpeed);
        }
        public void MoveDown()
        {
            RotateXAxis(angleSpeed);
        }
        private void RotateXAxis(float angleSpeed)
        {
            Rotate(XAxis, angleSpeed);//旋转
            Vector3 lastXAixs = XAxis;//保存上次的x轴
            SetDeviceView();//这里面XAxis的值发生了变化
            Vector3 newXAixs = XAxis;//现在的x轴值
            double flag = Vector3.Dot(lastXAixs, newXAixs);
            if (flag < 0)//旋转变化后x轴是否反方向了
            {
                //修改向上方向
                UpVector.X *= -1;
                UpVector.Y *= -1;
                UpVector.Z *= -1;
            }
        }
        private void RotateYAxis(float angleSpeed)
        {
            Rotate(ZAxis, angleSpeed);
            SetDeviceView();
        }
        private void Rotate(Vector3 xAxis, float angle)
        {
            //Console.Write("xAxis:({0},{1},{2})\n", xAxis.X, xAxis.Y, xAxis.Z);
            //WriteInfo();
            Vector4 tempV4 = Rotate(R, xAxis, angle);
            //Console.Write("tempV4:({0},{1},{2},{3}) {4}\n", tempV4.X, tempV4.Y, tempV4.Z, tempV4.W, tempV4.Length());
            Postion.X = Target.X + tempV4.X;
            Postion.Y = Target.Y + tempV4.Y;
            Postion.Z = Target.Z + tempV4.Z;
            //Console.Write("Postion:({0},{1},{2})\n", Postion.X, Postion.Y, Postion.Z);
        }
        public Vector3 R
        {
            get
            {
                Vector3 r = Postion;
                r.Subtract(Target);
                return r;
            }
        }
        public static Vector4 Rotate(Vector3 v, Vector3 axis, float angle)
        {
            Matrix rotateMatrix = Matrix.RotationQuaternion(Quaternion.RotationAxis(axis, angle));//用四元数得到旋转矩阵
            //Matrix rotateMatrix = Matrix.RotationAxis(xAxis, angle);
            Vector4 tempV4 = Vector3.Transform(v, rotateMatrix);
            return tempV4;
        }
        private void WriteInfo()
        {
            Vector3 r = R;
            Console.Write(" r:({0},{1},{2}) ", r.X, r.Y, r.Z);
            Vector3 v = Vector3.Cross(r, UpVector);//向量积
            Console.Write(" v:({0},{1},{2}) ", v.X,v.Y,v.Z);
            double len = v.Length();
            Console.Write(" len:{0} ", len);
            double sin = len / R.Length() * UpVector.Length();
            Console.Write(" sin:{0} ", sin);
            double angle = Math.Asin(sin)*180/Math.PI;
            Console.Write(" angle:{0}", angle);
            Console.Write("\n");
        }
        /// <summary>
        /// 旋转摄像头
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public void Rotate(int x, int y, int width, int height)
        {
            float tempAngleY = 2 * (float)(x - _mouseLastX) / width;
            Postion.Subtract(Target);
            Vector4 tempV4 = Vector3.Transform(Postion, Matrix.RotationQuaternion(Quaternion.RotationAxis(YAxis, tempAngleY)));
            Postion.X = tempV4.X;
            Postion.Y = tempV4.Y;
            Postion.Z = tempV4.Z;
            float tempAngleX = 4 * (float)(y - _mouseLastY) / height;
            tempV4 = Vector3.Transform(Postion, Matrix.RotationQuaternion(Quaternion.RotationAxis(XAxis, tempAngleX)));
            Postion.X = tempV4.X + Target.X;
            Postion.Y = tempV4.Y + Target.Y;
            Postion.Z = tempV4.Z + Target.Z;
            SetDeviceView();
            _mouseLastX = x;
            _mouseLastY = y;
        }
        /// <summary>
        /// 拉近拉远摄像头
        /// </summary>
        /// <param name="data"></param>
        public void Scale(float data)
        {
            Postion.Subtract(Target);
            Postion.Scale(data);
            Postion.Add(Target);
            //ZNearPlane *= data;
        }
        /// <summary>
        /// 拉近拉远摄像头
        /// </summary>
        /// <param name="data"></param>
        public void Zoom(int data)
        {
            float scaleFactor = -(float)data / 2000 + 1f;
            Scale(scaleFactor);
            SetDeviceView();
        }
        public void SetDeviceView()
        {
            device.Transform.View = Matrix.LookAtLH(Postion, Target, UpVector);
        }
        /// <summary>
        /// 计算视图矩阵,和Matrix.LookAtLH()一样
        /// </summary>
        /// <returns></returns>
        public Matrix GetMatrix()
        {
            Vector3 zAxis = Vector3.Normalize(Target - Postion);
            Vector3 xAxis = Vector3.Normalize(Vector3.Cross(UpVector, zAxis));
            Vector3 yAxis = Vector3.Cross(zAxis, xAxis);
            Matrix vm = Matrix.Zero;
            vm.M11 = xAxis.X; vm.M12 = yAxis.X; vm.M13 = zAxis.X;
            vm.M21 = xAxis.Y; vm.M22 = yAxis.Y; vm.M23 = zAxis.Y;
            vm.M31 = xAxis.Z; vm.M32 = yAxis.Z; vm.M33 = zAxis.Z;
            vm.M41 = -Vector3.Dot(xAxis, Postion);
            vm.M42 = -Vector3.Dot(yAxis, Postion);
            vm.M43 = -Vector3.Dot(zAxis, Postion);
            vm.M44 = 1;
            return vm;
        }
    }

}

下面是在一个3D显示控件中的使用:

#region 摄像头
        public bool AutoFocus { get; set; }
        protected override void OnMouseEnter(EventArgs e)
        {
            if (AutoFocus)
            {
                this.Focus();
            }
            base.OnMouseEnter(e); 
        }
        protected override void OnKeyDown(KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Left:
                    Camera.MoveLeft();
                    break;
                case Keys.Right:
                    Camera.MoveRight();
                    break;
                case Keys.Up:
                   Camera.MoveUp();
                    break;
                case Keys.Down:
                    Camera.MoveDown();
                    break;
                case Keys.Add:
                    Camera.Scale(0.95f);
                    break;
                case Keys.Subtract:
                    Camera.Scale(1.05f);
                    break;
                case Keys.Enter:
                    Vector3[] points = new Vector3[8];
                    points[0] = new Vector3(30f, 20f, 0f);
                    points[1] = new Vector3(30f, 20f, 10f);
                    points[2] = new Vector3(40f, 20f, 0f);
                    points[3] = new Vector3(40f, 20f, 10f);
                    points[4] = new Vector3(30f, 10f, 0f);
                    points[5] = new Vector3(30f, 10f, 10f);
                    points[6] = new Vector3(40f, 10f, 0f);
                    points[7] = new Vector3(40f, 10f, 10f);
                    DrawHexClass drawTri = new DrawHexClass(Device, points);
                    drawTri.DrawHex();
                    break;
            }
            DrawDevice();//重绘
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            this.Focus();
            if (e.Button == MouseButtons.Left)
            {
                Camera.StartChange(e.X,e.Y,CameraMode.Rotate);
            }
            else if (e.Button == MouseButtons.Middle)
            {
                Camera.StartChange(e.X, e.Y, CameraMode.Move);
            }
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            Camera.EndChange();
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            Camera.Change(e.X, e.Y, this.Width, this.Height);
            DrawDevice();//重绘
        }
        /// <summary>
        /// 必须在获得焦点的情况下才能响应
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            Camera.Zoom(e.Delta);
            DrawDevice();
        }
        #endregion

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值