using OpenTK.Mathematics;
|
|
namespace Yw.WinFrmUI.Hydro
|
{
|
/// <summary>
|
/// 2d正交相机
|
/// </summary>
|
internal class OrthoCamera2d
|
{
|
/// <summary>
|
/// 辅助类
|
/// </summary>
|
public OrthoCamera2d() { }
|
|
/// <summary>
|
/// 旋转
|
/// </summary>
|
public Vector3 Rotation
|
{
|
get => _rotation;
|
set => _rotation = value;
|
}
|
private Vector3 _rotation = Vector3.Zero;
|
|
/// <summary>
|
/// 平移
|
/// </summary>
|
public Vector3 Translation
|
{
|
get => _translation;
|
set => _translation = value;
|
}
|
private Vector3 _translation = Vector3.Zero;
|
|
/// <summary>
|
/// 投影矩阵
|
/// </summary>
|
public Matrix4 ProjectionMatrix
|
{
|
get => _projectionMatrix;
|
set => _projectionMatrix = value;
|
}
|
private Matrix4 _projectionMatrix = Matrix4.Identity;
|
|
/// <summary>
|
/// 视图矩阵
|
/// </summary>
|
public Matrix4 ViewMatrix
|
{
|
get => _viewMatrix;
|
set => _viewMatrix = value;
|
}
|
private Matrix4 _viewMatrix = Matrix4.Identity;
|
|
/// <summary>
|
/// 模型矩阵
|
/// </summary>
|
public Matrix4 ModelMatrix
|
{
|
get => _modelMatrix;
|
set => _modelMatrix = value;
|
}
|
private Matrix4 _modelMatrix = Matrix4.Identity;
|
|
/// <summary>
|
/// 缩放
|
/// </summary>
|
public float Zoom
|
{
|
get => _zoom;
|
set => _zoom = MathHelper.Clamp(value, 0.01f, 100.0f); // 限制缩放范围
|
}
|
private float _zoom = 1.0f; // 当前缩放系数(1表示原始大小)
|
|
private BoundingBox3 _bx = null;
|
private Vector3 _center = Vector3.Zero;
|
private float _radius = 100f;//包围球半径
|
private float _width, _height, _aspect;//视口宽度和高度与宽高比
|
private float _pw, _ph;//投影宽度和高度
|
|
/// <summary>
|
/// 初始化
|
/// </summary>
|
public void Initial(List<Vector3> vers, int width, int height)
|
{
|
UpdateViewPort(width, height);
|
if (vers == null || vers.Count < 1)
|
{
|
vers = new List<Vector3>()
|
{
|
new Vector3(-_width/2f,-_height/2f,-100f),
|
new Vector3(width/2f,height/2f,100f)
|
};
|
}
|
_bx = new BoundingBox3(vers);
|
_center = _bx.Center;
|
_radius = _bx.Size.Length / 2f * 1.2f;
|
UpdateMatrices();
|
}
|
|
/// <summary>
|
/// 更新视口
|
/// </summary>
|
public void UpdateViewPort(int width, int height)
|
{
|
_width = width < 1 ? 1f : width;
|
_height = height < 1 ? 1f : height;
|
_aspect = _width / _height;
|
}
|
|
/// <summary>
|
/// 更新缩放
|
/// </summary>
|
public void UpdateZoom(float scale)
|
{
|
this.Zoom *= scale;
|
}
|
|
/// <summary>
|
/// 更新平移
|
/// </summary>
|
public void UpdateTranslation(float dx, float dy)
|
{
|
float xratio = _pw / _width;
|
float yratio = _ph / _height;
|
_translation.X += dx * xratio;
|
_translation.Y -= dy * yratio;
|
}
|
|
/// <summary>
|
/// 更新旋转
|
/// </summary>
|
public void UpdateRotation(float dx, float dy)
|
{
|
_rotation.X += dy / _radius;
|
_rotation.Y += dx / _radius;
|
_rotation.X = NormalizeAngle(_rotation.X);
|
_rotation.Y = NormalizeAngle(_rotation.Y);
|
}
|
|
/// <summary>
|
/// 更新模型矩阵
|
/// </summary>
|
public void UpdateModelMatrix()
|
{
|
_modelMatrix = Matrix4.CreateRotationX(_rotation.X) *
|
Matrix4.CreateRotationY(_rotation.Y) *
|
Matrix4.CreateTranslation(_translation * this.Zoom);
|
}
|
|
/// <summary>
|
/// 更新视图矩阵
|
/// </summary>
|
public void UpdateViewMatrix()
|
{
|
var eye = new Vector3(_center.X, _center.Y, _center.Z + 2f * _radius);
|
var target = _center;
|
var up = Vector3.UnitY;
|
_viewMatrix = Matrix4.LookAt(eye, target, up);
|
}
|
|
/// <summary>
|
/// 更新投影矩阵
|
/// </summary>
|
public void UpdateProjectionMatrix()
|
{
|
_pw = _ph = _radius * 2f;
|
if (_aspect > 1)
|
{
|
_pw *= _aspect;
|
}
|
else
|
{
|
_ph /= _aspect;
|
}
|
_projectionMatrix = Matrix4.CreateOrthographic(_pw * this.Zoom, _ph * this.Zoom, _radius, _radius * 3f);
|
}
|
|
/// <summary>
|
/// 更新举证
|
/// </summary>
|
public void UpdateMatrices()
|
{
|
UpdateModelMatrix();
|
UpdateViewMatrix();
|
UpdateProjectionMatrix();
|
}
|
|
//标准化旋转弧度
|
private static float NormalizeAngle(float angle)
|
{
|
// 取余操作
|
angle %= 2 * MathF.PI;
|
|
// 如果结果为负数,加上 2π 使其处于 [0, 2π) 区间
|
if (angle < 0)
|
{
|
angle += 2 * MathF.PI;
|
}
|
|
return angle;
|
}
|
|
|
|
}
|
}
|