using o0.Geometry2D.Float; using System; using UnityEngine; namespace ZIM.Unity { // 摄像机的取景画面的纵横比设置(取景画面纵横比是否会根据分辨率变化) public enum AspectRatioSetting { FixedAll, // 高度和宽度都不变 FixedHeight, // 高度固定 FixedWidth, // 宽度固定 } // 记录屏幕的位置,QuadInCamera表示屏幕4个点在摄像机画面中的坐标 // TransformToScreen可将摄像机空间的点映射到屏幕空间,反之用TransformToCamera public class ScreenMap { public static AspectRatioSetting ViewAspectRatioSetting = AspectRatioSetting.FixedHeight;// 默认取景画面的高度保持不变,宽度随着分辨率变化 public Rect QuadRect { get; private set; } public Vector2 UVSize { get; private set; } // UV代表屏幕空间的坐标,UVSize代表屏幕坐标的取值范围 public bool Active; QuadrilateralInCamera quadInCamera; // 记录的分辨率和识别时的分辨率可能不同 public QuadrilateralInCamera QuadInCamera { get => quadInCamera; set { quadInCamera = value; InitByQuad(); } } // 当分辨率不同时,刷新分辨率并返回true,否则返回false public bool RefreshCameraSize(Vector2 sizeNew) => RefreshCameraSize(sizeNew.o0Vector()); public bool RefreshCameraSize(Vector sizeNew) { if (QuadInCamera != null && QuadInCamera.CameraSize != sizeNew) { Debug.Log($"[ScreenMap]根据分辨率映射: from {QuadInCamera.SizeString} to ({sizeNew.x}, {sizeNew.y})"); QuadInCamera.ReSize(sizeNew, ViewAspectRatioSetting); InitByQuad(); return true; } return false; } private void InitByQuad() { if (QuadInCamera != null) { var quad = QuadInCamera.Quad; var x = Math.Min((quad.A - quad.B).Length, (quad.C - quad.D).Length); var y = Math.Min((quad.A - quad.C).Length, (quad.B - quad.D).Length); UVSize = new Vector2(x, y); perspective = new ZIMPerspectiveTransform(quad, new OrdinalQuadrilateral(new Vector(0, 0), new Vector(x, 0), new Vector(0, y), new Vector(x, y))); var aabb = quad.AABBRect(); QuadRect = new Rect(aabb.Item1.x, aabb.Item1.y, aabb.Item2.x - aabb.Item1.x, aabb.Item2.y - aabb.Item1.y); Debug.Log("[ScreenMap] 应用屏幕识别数据"); //Debug.Log("QuadRect:" + QuadRect); Active = true; } else { Active = false; } } private ZIMPerspectiveTransform perspective; public ScreenMap() { } public ScreenMap(QuadrilateralInCamera quad) { QuadInCamera = quad; } public bool UVInScreen(Vector2 v) { return Active ? v.x > 0 && v.x < UVSize.x && v.y > 0 && v.y < UVSize.y : true; } // UV归一化到[0, 1]范围,仅用于输出最终结果 public Vector2 UVNormalized(Vector2 location) { return Active ? new Vector2(location.x / UVSize.x, location.y / UVSize.y) : new Vector2(location.x / ScreenLocate.Main.CameraSize.x, location.y / ScreenLocate.Main.CameraSize.y); } public Vector2 TransformToScreen(Vector2 vIn) { if (Active) { var v = perspective.Transform(vIn.x, vIn.y); return new Vector2(v.x, v.y); } else { return vIn; } } public Vector2 TransformToCamera(Vector2 vIn) { if (Active) { var v = perspective.TransformInverse(vIn.x, vIn.y); return new Vector2(v.x, v.y); } else { return vIn; } } } }