using OpenTK.GLControl;
|
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Mathematics;
|
|
namespace Yw.WinFrmUI.Hydro
|
{
|
/// <summary>
|
/// 正交相机
|
/// </summary>
|
internal class Ortho2dCamera
|
{
|
|
// 基础参数
|
private List<Vector3> _pts = null; //所有坐标
|
private BoundingBox3 _wbx;//世界包围盒
|
private BoundingBox3 _vbx;//视图包围盒
|
private float _baseSize = 10f;//基础尺寸
|
private float _orthoWidth = 10f;//正交宽度
|
private float _orthoHeight = 10f;//正交高度
|
private float _orthoNear = 0.1f;//正交近截面
|
private float _orthoFar = 10f;//正交远截面
|
private float _aspect = 1f;//视口宽高比
|
private Vector3 _rotation = Vector3.Zero;//旋转量
|
private Vector3 _translation = Vector3.Zero;//平移量
|
|
/// <summary>
|
/// 投影矩阵
|
/// </summary>
|
public Matrix4 ProjectionMatrix => _projectionMatrix;
|
private Matrix4 _projectionMatrix;
|
|
/// <summary>
|
/// 视图模型
|
/// </summary>
|
public Matrix4 ViewMatrix
|
{
|
get
|
{
|
return _viewMatrix;
|
}
|
}
|
private Matrix4 _viewMatrix;
|
|
/// <summary>
|
/// 模型矩阵
|
/// </summary>
|
public Matrix4 ModelMatrix => _modelMatrix;
|
private Matrix4 _modelMatrix;
|
|
public Vector3 Translation => _translation;
|
public Vector3 Rotation => _rotation;
|
|
/// <summary>
|
/// 缩放
|
/// </summary>
|
public float Zoom
|
{
|
get => _zoom;
|
set => _zoom = MathHelper.Clamp(value, 0.01f, 100.0f); // 限制缩放范围
|
}
|
private float _zoom = 1.0f; // 当前缩放系数(1表示原始大小)
|
|
/// <summary>
|
/// 初始化
|
/// </summary>
|
public void Initial(List<Vector3> pts)
|
{
|
_pts = pts;
|
if (pts != null && pts.Count > 0)
|
{
|
_wbx = new BoundingBox3(pts);
|
_vbx = TransformBoundsToViewSpace(_wbx);
|
_baseSize = CalcuBaseSize(_vbx);
|
}
|
}
|
|
|
//世界包围盒=>视图包围盒
|
private BoundingBox3 TransformBoundsToViewSpace(BoundingBox3 worldBounds)
|
{
|
var corners = worldBounds.GetCorners();
|
Vector3 min = new(float.MaxValue);
|
Vector3 max = new(float.MinValue);
|
var qua = new Quaternion(_rotation);
|
|
foreach (var corner in corners)
|
{
|
Vector3 viewPos = Vector3.Transform(corner, qua);
|
min = Vector3.ComponentMin(min, viewPos);
|
max = Vector3.ComponentMax(max, viewPos);
|
}
|
|
return new BoundingBox3(min, max);
|
}
|
|
//计算基础尺寸
|
private float CalcuBaseSize(BoundingBox3 vbx)
|
{
|
var halfX = Math.Max(Math.Abs(vbx.Max.X), Math.Abs(vbx.Min.X));
|
var halfY = Math.Max(Math.Abs(vbx.Max.Y), Math.Abs(vbx.Min.Y));
|
var halfZ = Math.Max(Math.Abs(vbx.Max.Z), Math.Abs(vbx.Min.Z));
|
var baseSize = Math.Max(halfX, Math.Max(halfY, halfZ));
|
return baseSize * 2f;
|
}
|
|
//更新视口
|
public void UpdateViewport(int width, int height)
|
{
|
var w = width < 1 ? 1 : width;
|
var h = height < 1 ? 1 : height;
|
_aspect = w / (float)h;
|
GL.Viewport(0, 0, w, h);
|
}
|
|
/// <summary>
|
/// 更新模型矩阵
|
/// </summary>
|
public void UpdateModelMatrix()
|
{
|
var center = (_vbx.Min + _vbx.Max) * 0.5f;
|
_modelMatrix = Matrix4.CreateTranslation(-center);
|
}
|
|
/// <summary>
|
/// 更新视图矩阵
|
/// </summary>
|
public void UpdateViewMatrix()
|
{
|
var center = (_vbx.Min + _vbx.Max) * 0.5f;
|
var eye = center + new Vector3(0, 0, _baseSize + 0.1f);
|
|
// 视图矩阵:将场景中心对齐到视口中心
|
_viewMatrix = Matrix4.LookAt(
|
eye, // 摄像机位置
|
Vector3.Zero,// 观察目标
|
Vector3.UnitY); // 上方向
|
}
|
|
//更新投影矩阵
|
public void UpdateProjectionMatrix()
|
{
|
float width = _baseSize;
|
float height = _baseSize;
|
if (_aspect > 1)
|
{
|
width = _baseSize * _aspect;
|
}
|
else
|
{
|
height = _baseSize / _aspect;
|
}
|
width *= this.Zoom;
|
height *= this.Zoom;
|
|
|
// 设置正交投影矩阵
|
_projectionMatrix = Matrix4.CreateOrthographic(
|
width,
|
height,
|
0.1f, // zNear
|
_baseSize + 0.1f // zFar (包含模型高度)
|
);
|
}
|
|
#region 鼠标交互
|
|
private Vector2 _lastMousePos;//最后一次鼠标位置
|
private bool _isDragging = false;//是否增在拖动
|
private bool _isRotating = false;//是否正在旋转
|
|
/// <summary>
|
/// 处理鼠标滚轮
|
/// </summary>
|
public void HandleMouseWheel(GLControl gl, MouseEventArgs e)
|
{
|
this.Zoom *= e.Delta > 0 ? 0.9f : 1.1f;
|
UpdateProjectionMatrix();
|
gl.Invalidate();
|
}
|
|
/// <summary>
|
/// 处理鼠标按下
|
/// </summary>
|
public void HandleMouseDown(GLControl gl, MouseEventArgs e)
|
{
|
if (e.Button == MouseButtons.Right)
|
{
|
_isDragging = true;
|
_lastMousePos = new Vector2(e.X, e.Y);
|
gl.Cursor = Cursors.SizeAll; // 修改光标样式
|
}
|
else if (e.Button == MouseButtons.Left)
|
{
|
_isRotating = true;
|
_lastMousePos = new Vector2(e.X, e.Y);
|
gl.Cursor = Cursors.SizeAll; // 修改光标样式
|
}
|
}
|
|
/// <summary>
|
/// 处理鼠标弹起
|
/// </summary>
|
public void HandleMouseUp(GLControl gl, MouseEventArgs e)
|
{
|
if (e.Button == MouseButtons.Right)
|
{
|
_isDragging = false;
|
gl.Cursor = Cursors.Default;
|
}
|
else if (e.Button == MouseButtons.Left)
|
{
|
_isRotating = false;
|
gl.Cursor = Cursors.Default;
|
}
|
}
|
|
/// <summary>
|
/// 处理鼠标移动
|
/// </summary>
|
public void HandleMouseMove(GLControl gl, MouseEventArgs e)
|
{
|
if (_isDragging)
|
{
|
Vector2 currentPos = new Vector2(e.X, e.Y);
|
Vector2 delta = currentPos - _lastMousePos;
|
_lastMousePos = currentPos;
|
// 计算平移量(Y轴方向需要反转)
|
_translation.X += delta.X / this.Zoom;
|
_translation.Y -= delta.Y / this.Zoom;
|
|
gl.Invalidate();
|
}
|
else if (_isRotating)
|
{
|
Vector2 currentPos = new Vector2(e.X, e.Y);
|
Vector2 delta = currentPos - _lastMousePos;
|
_lastMousePos = currentPos;
|
_rotation.X -= delta.Y;
|
_rotation.Y += delta.X;
|
_vbx = TransformBoundsToViewSpace(_wbx);
|
_baseSize = CalcuBaseSize(_vbx);
|
// UpdateModelMatrix();
|
//UpdateViewMatrix();
|
//UpdateProjectionMatrix();
|
gl.Invalidate();
|
}
|
}
|
|
|
#endregion
|
|
|
}
|
}
|