下面是完整的类:
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