using OpenTK.Mathematics; namespace Yw.WinFrmUI.Hydro { /// /// 2d正交相机 /// internal class OrthoCamera2d { /// /// 辅助类 /// public OrthoCamera2d() { } /// /// 旋转 /// public Vector3 Rotation { get => _rotation; set => _rotation = value; } private Vector3 _rotation = Vector3.Zero; /// /// 平移 /// public Vector3 Translation { get => _translation; set => _translation = value; } private Vector3 _translation = Vector3.Zero; /// /// 投影矩阵 /// public Matrix4 ProjectionMatrix { get => _projectionMatrix; set => _projectionMatrix = value; } private Matrix4 _projectionMatrix = Matrix4.Identity; /// /// 视图矩阵 /// public Matrix4 ViewMatrix { get => _viewMatrix; set => _viewMatrix = value; } private Matrix4 _viewMatrix = Matrix4.Identity; /// /// 模型矩阵 /// public Matrix4 ModelMatrix { get => _modelMatrix; set => _modelMatrix = value; } private Matrix4 _modelMatrix = Matrix4.Identity; /// /// 缩放 /// 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;//投影宽度和高度 /// /// 初始化 /// public void Initial(List vers, int width, int height) { UpdateViewPort(width, height); if (vers == null || vers.Count < 1) { vers = new List() { 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(); } /// /// 更新视口 /// public void UpdateViewPort(int width, int height) { _width = width < 1 ? 1f : width; _height = height < 1 ? 1f : height; _aspect = _width / _height; } /// /// 更新缩放 /// public void UpdateZoom(float scale) { this.Zoom *= scale; } /// /// 更新平移 /// public void UpdateTranslation(float dx, float dy) { float xratio = _pw / _width; float yratio = _ph / _height; _translation.X += dx * xratio; _translation.Y -= dy * yratio; } /// /// 更新旋转 /// 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); } /// /// 更新模型矩阵 /// public void UpdateModelMatrix() { _modelMatrix = Matrix4.CreateRotationX(_rotation.X) * Matrix4.CreateRotationY(_rotation.Y) * Matrix4.CreateTranslation(_translation * this.Zoom); } /// /// 更新视图矩阵 /// 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); } /// /// 更新投影矩阵 /// 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); } /// /// 更新举证 /// 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; } } }